【问题标题】:generated accessors to private fields of outer classes in java在java中生成对外部类的私有字段的访问器
【发布时间】:2014-07-30 12:33:30
【问题描述】:

所以我有一个关于 javac 生成的访问器(版本 1.7.0_65)允许内部类访问外部类的私有字段的问题。

首先,这里有一个短代码sn-p:

public class A {
    private int f = 0;

    class AA {
        public int m() {
            return f;
        }
    }
}

编译器在类 A 中生成一个访问器方法,以便方法 m 能够读取并返回 f 的值。

此访问器如下所示:

static int access$0(A);
    flags: ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: getfield      #12                 // Field f:I
         4: ireturn       

我的问题是:为什么这个访问器是作为静态方法生成的?是否存在非静态方法不起作用的情况?

【问题讨论】:

  • @PatrickJAbareII 他的 IDE 没有生成任何东西,javac 是。

标签: java inner-classes accessor


【解决方案1】:

这是因为在您的程序加载运行之前,内存中必须有任何支持您的代码的方法(这样就不会发生编译错误)。我们知道,静态方法在非静态成员(变量和方法)之前加载到内存中。此外,该访问器方法由 JVM 线程调用。 JVM 线程可以访问静态方法。

【讨论】:

    【解决方案2】:

    IMO 做出此决定有(至少)两个原因:

    首先:如果方法不是静态的,那么子类可能会覆盖它!

    由于编译器无法确定运行时的类与编译时看到的类相同,因此无法生成一致的不相交命名。

    考虑这个例子:

    public class A {
    
        private int x = 1;
    
        private class AA {
            public int f() {
                return x; // would call access$0 on the outer instance
            }
        }
        public int getX() {
            return new AA().f();
        }
    }
    public class B extends A {
    
        private int y = 2;
    
        private class BB {
            public int g() {
                return y;
            }
        }
    }
    

    如果该方法不是静态的,下面的代码将产生 2 而不是 1:

    assertEquals(new B().getX(), 2);
    

    第二:访问器方法也必须可用于静态内部类。

    【讨论】:

    • 不确定在您提供的示例中如何获得结果 2。
    • 因为在 AA.f() 中获取字段 A.x 将被编译为实例方法 access$0 的方法调用。由于也为 B 定义了 access$0,因此它将调用 B.access$0。这应该只是一个例子,如果合成访问方法不是静态的会发生什么。
    • 是的,但是 B.access$0 如何返回 2?
    • 因为 access$0 在 B 中被覆盖返回字段 B.y
    • 您是否使用 javap 确认了这一点?因为我看不到它如何访问 $0 被覆盖。
    猜你喜欢
    • 2018-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    相关资源
    最近更新 更多