为什么默认访问权限可以简化嵌套类访问过程

查看ArrayList源码时看到

1
transient Object[] elementData; // non-private to simplify nested class access

有点好奇使用默认权限而不是私有权限是怎么简化嵌套类访问过程的,先在Google中搜索相关内容,只找到对于这行代码中transientObject[]的讨论,所以我写了个测试类,然后查看两种权限下该类生成的字节码中有哪些差异。类的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CanNestedClassUsePrivateMember {
private int whatever;

class Inner {
void access() {
System.out.println(whatever);
}
}

public static void main(String[] args) {
new CanNestedClassUsePrivateMember().new Inner().access();
}
}

diff结果可以查看DiffChecker上的结果

private下差异主要是多了以下字节码:

1
2
3
4
5
6
7
8
9
10
11
12
  MAXLOCALS = 1		

// access flags 0x1008
static synthetic access$000(Ltech/zuosi/javaenhance/basic/CanNestedClassUsePrivateMember;)I
L0
LINENUMBER 3 L0
ALOAD 0
GETFIELD tech/zuosi/javaenhance/basic/CanNestedClassUsePrivateMember.whatever : I
IRETURN
L1
LOCALVARIABLE x0 Ltech/zuosi/javaenhance/basic/CanNestedClassUsePrivateMember; L0 L1 0
MAXSTACK = 1

字节码暂时没怎么研究,现阶段我猜测这段代码是生成了一个静态的访问方法用于获取private修饰的whatever域。

所以non-private确实简化了嵌套类对该域的访问过程。

之后弄懂字节码后再来作进一步分析0.0

这里还可以引申到Java的嵌套类实际是怎么样的,是不是编译后就是一个独立的类,只是包装了一些方法来引用外部类的域和方法。


2017/10/20 22:21 更新
2017/12/04 08:50 更新有关名称中美元符号的内容

之前的猜测差不多是正确的,当外部类的字段被private所修饰时,编译器会生成静态的访问方法来提供给内部类访问,而带有则避免了和已有方法和已有字段的冲突(名称中带有$的可以通过编译),同时也只有class文件中能够访问该类方法/字段(生成的方法在编译前是不存在的)。

JLS中提到

The “Java letters” include uppercase and lowercase ASCII Latin letters A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical reasons, the ASCII underscore (_, or \u005f) and dollar sign ($, or \u0024). The $ sign should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems.

$应该只用在生成的代码中,或者用来访问历史遗留系统中的预置名称。

生成的getter和setter类方法,第一个字段都是外部类的实例对象,而每个内部类在被实例化时会有一个外部类的实例对象,所以内部类能够最终通过访问外部类中的静态方法来访问私有字段。

当外部类字段不加访问修饰符时,默认作用域为package-private,即包级私有,此时同一个包下的其他类都可以访问,而内部类在编译后是独立的一个类,类名为外部类$内部类,并且处于同一个包下,所以此时内部类可以直接访问包级私有的外部类字段。

因此non-private确实是简化了访问过程,编译器不需要在外部类中生成静态访问方法,也不需要在内部类访问外部类字段时调用合成的方法。

Oracle官网上的Java教程中提到嵌套类(nested class)分为两类:静态嵌套类(static nested class)和内部类(inner class)