如果在 IntelliJ IDEA 中调试 Java 时变量的名称为 "this[=10=]",这意味着什么?
What does it mean if a variable has the name "this$0" in IntelliJ IDEA while debugging Java?
我试图理解 this Functional Reactive Java library by running a test 在调试模式下调用 testSendStream
并在测试执行时单步执行代码。
上面的快照显示有一个名为 this[=13=]
的奇怪命名的变量。
这个名字从何而来?
这个名字是什么意思?
为什么这个变量有这个名字?
给它起这个名字的原因是什么?
当然这个名字不是来自代码本身,它是由 IntelliJ 或 javac/java 生成的。但是为什么?
如果我用标签 Mystery Object
标记这个对象,看看会发生什么也很有趣。
这是一个与非静态内部 classes 相关的约定。内部 class 的字节码将包含对名为 this[=10=]
的包范围字段的引用,该字段允许您引用封闭 class 的 this 对象。请注意,在您的示例中 this[=10=]
与上面定义的 Mystery Object this
变量相同。
this[=17=]
是 "hidden field" in Inner
class(非静态 嵌套 class)用于保存对 Outer
class 实例的引用,该实例用于创建内部 class.
的当前实例
简而言之,当你有
Outer outer = new Outer();
Outer.Inner inner = oc.new Outer.Inner();
Inner
由 inner
持有的实例将在其 this[=17=]
字段中存储对用于创建它的 Outer
实例的引用(与 [=24= 持有的引用相同) ]变量)。
这是必要的,因为嵌套的 classes 必须能够访问外部 classes 的所有成员(包括私有成员)。如果我们希望能够在内部 class 中编写类似 methodFromOuterClass();
的内容,JVM 需要知道它应该在哪个 Outer
实例上调用此方法。使编译器 "changes" 这样的代码成为可能 this[=27=].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
的值?
这是因为 inner class 的每个实例都知道它是在 outer class 的哪个实例上创建的。这是因为 this[=17=]
引用存储了对用于创建内部实例的外部实例的引用。
此变量由编译器添加到所有非静态内部 classes,并在您调用
时设置其值
Outer.Inner in1 = o1.new Inner(); //`this[=14=]` will be set to hold `o1` instance.
所以代码像
void printOuterID(){
System.out.println(id);
}
本质上等于
void printOuterID(){
System.out.println(this[=16=].id); //although we can't access this[=16=] explicitly
}
我试图理解 this Functional Reactive Java library by running a test 在调试模式下调用 testSendStream
并在测试执行时单步执行代码。
上面的快照显示有一个名为 this[=13=]
的奇怪命名的变量。
这个名字从何而来?
这个名字是什么意思?
为什么这个变量有这个名字?
给它起这个名字的原因是什么?
当然这个名字不是来自代码本身,它是由 IntelliJ 或 javac/java 生成的。但是为什么?
如果我用标签 Mystery Object
标记这个对象,看看会发生什么也很有趣。
这是一个与非静态内部 classes 相关的约定。内部 class 的字节码将包含对名为 this[=10=]
的包范围字段的引用,该字段允许您引用封闭 class 的 this 对象。请注意,在您的示例中 this[=10=]
与上面定义的 Mystery Object this
变量相同。
this[=17=]
是 "hidden field" in Inner
class(非静态 嵌套 class)用于保存对 Outer
class 实例的引用,该实例用于创建内部 class.
简而言之,当你有
Outer outer = new Outer();
Outer.Inner inner = oc.new Outer.Inner();
Inner
由 inner
持有的实例将在其 this[=17=]
字段中存储对用于创建它的 Outer
实例的引用(与 [=24= 持有的引用相同) ]变量)。
这是必要的,因为嵌套的 classes 必须能够访问外部 classes 的所有成员(包括私有成员)。如果我们希望能够在内部 class 中编写类似 methodFromOuterClass();
的内容,JVM 需要知道它应该在哪个 Outer
实例上调用此方法。使编译器 "changes" 这样的代码成为可能 this[=27=].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
的值?
这是因为 inner class 的每个实例都知道它是在 outer class 的哪个实例上创建的。这是因为 this[=17=]
引用存储了对用于创建内部实例的外部实例的引用。
此变量由编译器添加到所有非静态内部 classes,并在您调用
Outer.Inner in1 = o1.new Inner(); //`this[=14=]` will be set to hold `o1` instance.
所以代码像
void printOuterID(){
System.out.println(id);
}
本质上等于
void printOuterID(){
System.out.println(this[=16=].id); //although we can't access this[=16=] explicitly
}