java - 方法中的类如何访问该方法的局部变量?

标签 java inner-classes

我知道所有局部变量都将存储在堆栈内存中,而对象和静态变量将存储在堆中。但是当我遇到以下让我感到困惑的代码时。

public class Outer {

   private int a =10;

   public void outerMethod() {      
      int x = 30;

       class Inner {
          private int b = 20;
          public void innerMethod() {
            System.out.println("The Value of a is: "+a);
            System.out.println("The Value of b is: "+b);
            System.out.println("The Value of x is: "+x);
          }
       };

       Inner inner = new Inner();
       inner.innerMethod();
    }   
}

上面的代码运行良好。但我的问题是x 是outerMethod() 的局部变量。当我们创建一个 Outer 类的对象,并在其上调用 outerMethod() 时,x 将存储在堆栈框架中,我还定义了一个内部类的类定义并创建了对象它,然后我在它上面调用 innerMethod() 。
所以Inner Class的对象必须存储在堆中。如果是这样,那么它如何访问 x??

最佳答案

Inner 只能访问 x 如果 x 是最终的(或者,来自 Java 8 effectively final )。在幕后,编译器会注意到 Inner 对象使用了哪些外部变量,并将它们传递给 Inner 构造函数(这些将是合成构造函数参数 - 由编译器,所以你不会看到它们)。然后它们将成为 Inner 类的最终(同样,合成 = 生成并向您隐藏)字段。当您在 Inner 类代码中引用 x 时,编译器会将其替换为对 中合成 x 字段的引用复制值的内部 类。

您可以使用这个有用的命令查看更多详细信息:

javac -d . -XD-printflat MyFile.java

会生成对应实际字节码的Java代码:

class Outer {

    /*synthetic*/ static int access$000(Outer x0) {
        return x0.a;
    }

    Outer() {
        super();
    }
    private int a = 10;

    public void outerMethod() {
        int x = 30;
        /*synthetic*/ {
        }
        ;
        Outer$1Inner inner = new Outer$1Inner(this, x);
        inner.innerMethod();
    }
}

class Outer$1Inner {
    /*synthetic*/ final Outer this$0;
    /*synthetic*/ final int val$x;

    Outer$1Inner(final Outer this$0, /*synthetic*/ final int val$x) {
        // Notice the synthetic references to the surrounding Outer object
        // and to the x local variable
        // Both become fields of Inner

        this.this$0 = this$0;
        this.val$x = val$x;
        super();
    }
    private int b = 20;

    public void innerMethod() {
        System.out.println("The Value of a is: " + Outer.access$000(this$0));
        System.out.println("The Value of b is: " + b);
        System.out.println("The Value of x is: " + val$x);
    }
}

您还可以注意到 Outer.a 是如何被访问的——因为 Inner 被编译成一个“普通的旧 Java 类”,它必须遵守可见性修饰符,所以JVM 不允许直接访问私有(private)字段 Outer.a。但是,在编译过程中,编译器会注意到你要从Inner访问这个字段,因为它是一个内部类,所以会生成一个访问器方法Outer.access$000()。由于 Inner 引用了 Outer 对象,它可以调用 Outer.access$000(referenceToOuter) 并获取 Outer 的值.a.

关于java - 方法中的类如何访问该方法的局部变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33718123/

相关文章:

javascript - 如何在 AngularJS 中使用 JSON 数组?

Java 确保类已解析

java - 如何更改 JVM 默认堆设置

java - Oracle 数据库连接 - 不使用 setUrl

java - 使用内部类进行子类化,仅序列化外部类

java - 抽象私有(private)内部类

java - 公共(public)类的私有(private)内部类的可见性

Java instanceof 内部类无法转换错误

java - 如何自定义自定义 http 错误代码返回的默认 html 文件

Java 作用域和生命周期(内部类)