Java 11之前内部类访问私有字段为何用合成方法而非直接getField?
为什么Java 11之前内部类私有字段访问需要合成静态方法?
现有如下类:
public class Sample1 { public class Inner { private int f; } void go() { Inner in = new Inner(); int value = in.f; } }
Java 11之前,go方法的字节码会调用一个自动生成的合成方法:
static int access$000(nestmates.Sample1$Inner); descriptor: (Lnestmates/Sample1$Inner;)I flags: ACC_STATIC, ACC_SYNTHETIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #1 // Field f:I 4: ireturn
调用位置的字节码如下:
0: new #2 // class nestmates/Sample1$Inner 3: dup 4: aload_0 5: invokespecial #3 // Method nestmates/Sample1$Inner."<init>":(Lnestmates/Sample1;)V 8: astore_1 9: aload_1 10: invokestatic #4 // Method nestmates/Sample1$Inner.access$000:(Lnestmates/Sample1$Inner;)I
问题解答
核心原因是Java早期的私有访问控制规则:私有成员只能被定义该成员的类本身直接访问。
从字节码层面看,外部类Sample1和内部类Sample1$Inner是两个完全独立的类文件。虽然Java语法允许外部类访问内部类的私有成员,但JVM本身并不认可这种“特殊关系”——它只认类的边界:Sample1不是Sample1$Inner,所以没有权限直接访问后者的私有字段f。
javac只能通过生成合成静态方法来绕过这个限制:这个access$000方法是Sample1$Inner的静态方法,属于类本身,自然有权限访问自己的私有字段f;外部类Sample1的go方法则通过调用这个静态方法,间接拿到f的值。
Java 11引入了基于嵌套的访问控制(Nest-Based Access Control),JVM新增了“嵌套成员(nestmate)”的概念:同一嵌套结构下的类(比如外部类和它的内部类)会被视为同一嵌套组,彼此可以直接访问对方的私有成员,不需要再生成这类合成方法。
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

