4

在阅读有关嵌套类的 Oracle 文档时,我发现这段代码的输出我无法理解。有人可以解释一下吗?

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

以下是此示例的输出:

x = 23
this.x = 1
ShadowTest.this.x = 0 //why is 0 printed here? why not 1 because "this" is the object of FirstLevel class.

原始代码可以在这里找到

4

2 回答 2

6

局部变量xshadowsthis.xShadowTest.this.x.

内部类this.x的实例变量 ( ) 隐藏了封闭类的实例变量(可以通过 访问ShadowTest.this.x)。

System.out.println("x = " + x); // prints the local variable passed to the method
System.out.println("this.x = " + this.x); // prints the instance variable of the inner class
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x); // prints the instance variable of the enclosing class instance
于 2015-11-11T08:53:38.193 回答
1

我觉得除了此处找到的文档之外还没有完全解释这一点,因此我将根据我最近的理解尝试更详细地介绍。

我已将ShadowClass外部类的名称NestedClasses更改为并将变量从 type 更改int为 type String

这是在第一个嵌套类中添加第二个嵌套类的示例,以显示如何NestedClasses.this.x在更深层的类中继续表现。

public class NestedClasses {
    
    public String x = "outer class variable";
    
    class FirstLevel {

        public String x = "first level class variable";

        void methodInFirstLevel(String x) {
            System.out.println("methodInFirstLevel:");
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("NestedClasses.this.x = " + NestedClasses.this.x);
        }
        
        class SecondLevel {
            
            public String x = "second level class variable";

            void methodInSecondLevel(String x) {
                System.out.println("methodInSecondLevel:");
                System.out.println("x = " + x);
                System.out.println("this.x = " + this.x);
                System.out.println("NestedClasses.this.x = " + NestedClasses.this.x);
                System.out.println("FirstLevel.this.x = " + FirstLevel.this.x);
                System.out.println("NestedClasses.FirstLevel.this.x = " + NestedClasses.FirstLevel.this.x);
            }
        }
    }

    public static void main(String[] args) {

        NestedClasses st = new NestedClasses();
        NestedClasses.FirstLevel fl = st.new FirstLevel();
        NestedClasses.FirstLevel.SecondLevel sl = fl.new SecondLevel();

        fl.methodInFirstLevel("first level method arg");
        System.out.println();
        sl.methodInSecondLevel("second level method arg");
    }
}

输出:

methodInFirstLevel:
x= 一级方法 arg
this.x= 一级类变量
NestedClasses.this.x= 外部类变量

methodInSecondLevel:
x= 二级方法 arg
this.x= 二级类变量
NestedClasses.this.x= 外部类变量
FirstLevel.this.x= 一级类变量
NestedClasses.FirstLevel.this.x= 一级类变量

三个实例化对象(st, fl, sl)中的每一个都包含一个指向堆中不同内存空间x的指针,可以在其中找到 的值。我相信编译器正在向最外层“向后”搜索以找到第一个匹配的类,因为它看到的this是嵌套类中的类名前缀。它找到的第一个匹配类是它在确定需要搜索哪个对象实例化时将引用的类x。这意味着NestedClasses.FirstLevel.this.x实际上是向后退两步,向前一步来确定要查看堆中的哪个内存空间,即引用哪个内存空间x

总结:
NestedClasses.this.x

  • 前缀的类名NestedClasses告诉 JVM 正在使用哪个类,这个类必须在当前范围内是可访问的。
  • this关键字告诉 JVM 查看被引用类的实例化对象的内存空间,而不是类对象本身的内存空间(用于类的静态成员)。更具体地说,this将引用用于(并且需要)实例化非静态内部类的外部类的实例化。
  • x附加到的对象成员this告诉 JVM 在它正在查看的内存空间中搜索什么。
于 2020-12-22T00:30:58.087 回答