【问题标题】:How Member Class(Inner class) is accessing instance variable of outer class?成员类(内部类)如何访问外部类的实例变量?
【发布时间】:2015-01-22 13:55:44
【问题描述】:

我在下面编写了运行良好的代码,但我对合成方法有一点疑问。因为这些是为了访问私有数据而生成的。但是我有 public instance variable 的外部类在成员类中使用,所以为了访问实例变量它创建了 synthetic method (因为它在类文件中!! )。

代码 sn-p 为:

public class TestInnerClass {
    public int x = 10;
        public static void main(String[] args) {
            TestInnerClass test= new TestInnerClass();
            A obj = test.new A();
            obj.display();
        }

        class A {
            void display() {
            System.out.println(x);
        }
    }
}

类文件生成如下。 对于内部类 A 为 TestInnerClass$A:

import java.io.PrintStream;

class TestInnerClass$A {
    TestInnerClass$A(TestInnerClass paramTestInnerClass) {
    }

    void display() {
        System.out.println(this.this$0.x);
    }
}

为 TestInnerClass 生成类文件:

import java.io.PrintStream;
public class TestInnerClass {
    public int x = 10;
    public static void main(String[] args) { 
        TestInnerClass test = new TestInnerClass();
        TestInnerClass tmp13_12 = test; tmp13_12.getClass(); A obj = new A();
        obj.display();
   } 

   class A {
       A() {
       }
       void display() {
           System.out.println(TestInnerClass.this.x);
       }
   }
}

所以我的疑问是:

1)。为什么显示方法在类文件中有不同的定义??

2)。为什么 TestInnerClass 类文件中的实例变量以 TestInnerClass.this.x 的形式访问。但是相同的代码在 TestInnerClass$A 的类文件中与 this.this$0.x??

不同

3) 为什么 JVM 将合成方法创建为 this$0,但是 instance 变量是公共的??

【问题讨论】:

  • 代码正在运行。我有疑问!!
  • 好吧,我很惊讶地看到 new A() 可以作为实例的方法调用,如 A obj = test.new A(); 所示。我认为这不是有效的 Java 语法。你每天都会学到新东西。

标签: java inner-classes .class-file java-synthetic-methods


【解决方案1】:

不完全确定我是否理解您的问题,但我会尝试回答:

  1. 为什么显示方法在类文件中有不同的定义?

您无法将 java 文件与类文件进行比较。有些功能只存在于一个世界中。内部类就是这样一个特性。他们没有直接翻译成字节码。一些代码按摩是必要的,这就是您在这里发现的。

  1. 为什么在TestInnerClass 类文件中的实例变量被访问为TestInnerClass.this.x。但是TestInnerClass$A的类文件中的相同代码与this.this$0.x不同??

因为在编译内部类时,对外部类 (TestInnerClass.this) 的隐式引用被转换为显式引用。由于这个引用不能有标识符this,所以它被称为this$0。

  1. 为什么JVM创建合成方法为this$0,而实例变量是公开的??

这不是一种方法,据我所知,它不是公开的。它是一个存储对封闭类对象的引用的字段。需要它才能访问该对象的x。

【讨论】:

  • 可以看到代码变量x是public的!!并且相同方法的字节码生成不同!这就是我感到惊讶的地方。
  • 您的问题不清楚。 x 是一个变量。你在说什么“相同的方法”?
  • 是的,我认为它不应该生成。
  • 即使变量是公共的,内部对象仍然必须引用外部对象才能访问该公共变量。
  • 显然应该有,我同意你的看法。但是两个类文件都有不同的主体。所以我问了!!
【解决方案2】:

您可以从外部类访问变量,因为它们位于内部类的闭包中。 Closures 存在于 Java 中,但该概念不存在于 Java 字节码中。您看到的合成变量和访问器是使闭包在 java 字节码中工作所需的修饰的一部分。

完全披露:Java 中的闭包实际上并不是闭包。实际的闭包会捕获创建函数的整个环境。在 Java 中,内部类始终可以访问创建它的方法的外部类成员和最终局部变量。然而,它不能像 JavaScript 这样的语言那样访问非 final 局部变量。

【讨论】:

  • 只是对您的答案的一个小说明。我们实际上在 Java 中没有闭包,甚至在 java8 中也没有 lambda,因为它们只处理有效的最终变量。如果您查看其他语言(如 JavaScript)的闭包,该对象的寿命比创建它的方法长,但仍然可以访问该方法中的所有局部变量:) 谈到 OP 问题,在类中定义的内部类始终可以访问定义它们的类的成员(私有或公共)变量。
  • 添加了注释。我认为先从概念开始,然后再解释限制,而不是解释看似随意但有用的访问能力。
猜你喜欢
  • 2013-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-20
  • 1970-01-01
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多