这种行为在Java 5/6中是否仍然存在呢?
并不完全如描述的那样。我从未见过这种情况的编译器:
为了让这个独立类可以访问外部类的字段,编译器会悄悄地将这些字段从private更改为package范围!
相反,据我所知Sun Java 3/4创建了一个访问器而不是修改字段。
Sun Java 6 (javac 1.6.0_16) 创建了一个静态访问器:
public class InnerExample {
private int field = 42;
private class InnerClass {
public int getField () { return field; };
}
private InnerClass getInner () {
return new InnerClass();
}
public static void main (String...args) {
System.out.println(new InnerExample().getInner().getField());
}
}
$ javap -classpath bin -private InnerExample
Compiled from "InnerExample.java"
public class InnerExample extends java.lang.Object{
private int field;
public InnerExample();
private InnerExample$InnerClass getInner();
public static void main(java.lang.String[]);
static int access$000(InnerExample);
}
$ javap -classpath bin -c -private InnerExample
static int access$000(InnerExample);
Code:
0: aload_0
1: getfield #1;
4: ireturn
考虑到除了外部类和内部类以外的任何类都无法访问外部类的私有成员,那么这真的是一个安全隐患吗?
我这里有点猜测,但如果您编译该类,则不会出现问题,但是如果您添加了access$000
,那么可以编译使用访问器的代码。
import java.lang.reflect.*;
public class InnerThief {
public static void main (String...args) throws Exception {
for (Method me : InnerExample.class.getDeclaredMethods()){
System.out.println(me);
System.out.printf("%08x\n",me.getModifiers());
}
System.out.println(InnerExample.access$000(new InnerExample()));
}
}
有趣的是,合成的访问器具有修饰符标志
00001008
,而如果添加包级静态方法,则具有标志
00000008
。在JVM规范的第二版中没有关于该标志值的任何内容,但似乎可以防止javac看到该方法。
因此,似乎存在某些安全功能,但我找不到任何文档来说明这一点。
(因此发布此帖,以防万一有人知道类文件中0x1000的含义)