我试图通过在调试模式下运行名为testSendStream的test并在测试执行时逐步执行代码来理解this函数式React式Java库。
testSendStream
上面的快照显示有一个名称奇怪的变量this$0。
this$0
这个名字是从哪里来的?
这个名字是什么意思?
为什么这个变量有这个名字?
给它这个名字背后的理由是什么?
当然,这个名称不是来自代码本身,它是由IntelliJ或javac/Java生成的。但为什么呢?
看看如果我用标签Mystery Object标记这个对象会发生什么,也是很有趣的。
Mystery Object
6tdlim6h1#
thisE1d0d1e是Inner类(非静态嵌套类)中的“隐藏字段”,用于保存对Outer类的示例的引用,Outer类用于创建内部类的当前示例。
thisE1d0d1e
Inner
Outer
简而言之,当你有
Outer outer = new Outer(); Outer.Inner inner = outer.new Outer.Inner();
inner持有的Inner示例将在其this$0字段中存储对用于创建它的Outer示例的引用(与outer变量持有的引用相同)。
inner
outer
这是必要的,因为嵌套类必须能够访问外部类的所有成员(包括私有成员)。如果我们想要在内部类中编写类似methodFromOuterClass();的代码,JVM需要知道它应该在哪个Outer示例上调用此方法。为了使其成为可能,编译器将这样的代码“更改”为this$0.methodFromOuterClass()。
methodFromOuterClass();
this$0.methodFromOuterClass()
更多细节和示例:
public class Outer { private int id; public Outer(int id) { this.id = id;} public class Inner{ void printOuterID(){ System.out.println(id); } } }
现在,这里将打印什么?为什么?
Outer o1 = new Outer(1); Outer o2 = new Outer(2); Outer.Inner in1 = o1.new Inner(); Outer.Inner in2 = o2.new Inner(); in1.printOuterID(); in2.printOuterID();
我们拭目以待
1 2
但是in1怎么知道它应该从o1而不是从o2打印id的值呢?这是因为内部类的每个示例知道它是在外部类的哪个示例上创建的。这是因为this$0引用存储了用于创建内部示例的外部示例的引用。此变量由编译器添加到所有非静态内部类中,并在您调用
in1
o1
o2
id
Outer.Inner in1 = o1.new Inner(); //`thisB1a4a1b` will be set to hold `o1` instance.
所以像这样的代码
void printOuterID(){ System.out.println(id); //OR //System.out.println(Outer.this.id); }
被编译成
void printOuterID(){ System.out.println(thisB1a6a1b.id); //although we can't access thisB1a6a1b explicitly }
顺便说一句,如果您的内部类不需要访问其任何外部类的非静态成员,您可以将其更改为static class,这将去掉this$0字段。
static class
wydwbb8l2#
是与非静态内部类相关的约定。内部类的字节码将包含对名为this$0的包范围字段的引用,该字段允许您引用封闭类的This对象。请注意,在您的示例中,this$0与其上面定义的Mystery Object this变量相同。
Mystery Object this
2条答案
按热度按时间6tdlim6h1#
thisE1d0d1e
是Inner
类(非静态嵌套类)中的“隐藏字段”,用于保存对Outer
类的示例的引用,Outer
类用于创建内部类的当前示例。简而言之,当你有
inner
持有的Inner
示例将在其this$0
字段中存储对用于创建它的Outer
示例的引用(与outer
变量持有的引用相同)。这是必要的,因为嵌套类必须能够访问外部类的所有成员(包括私有成员)。如果我们想要在内部类中编写类似
methodFromOuterClass();
的代码,JVM需要知道它应该在哪个Outer
示例上调用此方法。为了使其成为可能,编译器将这样的代码“更改”为this$0.methodFromOuterClass()
。更多细节和示例:
现在,这里将打印什么?为什么?
我们拭目以待
但是
in1
怎么知道它应该从o1
而不是从o2
打印id
的值呢?这是因为内部类的每个示例知道它是在外部类的哪个示例上创建的。这是因为
this$0
引用存储了用于创建内部示例的外部示例的引用。此变量由编译器添加到所有非静态内部类中,并在您调用
所以像这样的代码
被编译成
顺便说一句,如果您的内部类不需要访问其任何外部类的非静态成员,您可以将其更改为
static class
,这将去掉this$0
字段。wydwbb8l2#
是与非静态内部类相关的约定。内部类的字节码将包含对名为
this$0
的包范围字段的引用,该字段允许您引用封闭类的This对象。请注意,在您的示例中,this$0
与其上面定义的Mystery Object this
变量相同。