在调试Java时,如果一个变量在IntelliJ Idea中的名称为“This$0”,这意味着什么?

tp5buhyn  于 2022-10-07  发布在  Java
关注(0)|答案(2)|浏览(223)

我试图通过在调试模式下运行名为testSendStreamtest并在测试执行时逐步执行代码来理解this函数式React式Java库。

上面的快照显示有一个名称奇怪的变量this$0

这个名字是从哪里来的?

这个名字是什么意思?

为什么这个变量有这个名字?

给它这个名字背后的理由是什么?

当然,这个名称不是来自代码本身,它是由IntelliJ或javac/Java生成的。但为什么呢?

看看如果我用标签Mystery Object标记这个对象会发生什么,也是很有趣的。

6tdlim6h

6tdlim6h1#

thisE1d0d1eInner类(非静态嵌套类)中的“隐藏字段”,用于保存对Outer类的示例的引用,Outer类用于创建内部类的当前示例。

简而言之,当你有

Outer outer = new Outer();
Outer.Inner inner = outer.new Outer.Inner();

inner持有的Inner示例将在其this$0字段中存储对用于创建它的Outer示例的引用(与outer变量持有的引用相同)。

这是必要的,因为嵌套类必须能够访问外部类的所有成员(包括私有成员)。如果我们想要在内部类中编写类似methodFromOuterClass();的代码,JVM需要知道它应该在哪个Outer示例上调用此方法。为了使其成为可能,编译器将这样的代码“更改”为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引用存储了用于创建内部示例的外部示例的引用。
此变量由编译器添加到所有非静态内部类中,并在您调用

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字段。

wydwbb8l

wydwbb8l2#

是与非静态内部类相关的约定。内部类的字节码将包含对名为this$0的包范围字段的引用,该字段允许您引用封闭类的This对象。请注意,在您的示例中,this$0与其上面定义的Mystery Object this变量相同。

相关问题