这种行为在 java 5 / 6 中是否仍然存在?
与描述的不完全一样;我从未见过这样的编译器:
为了允许这个单独的类访问外部类的字段,编译器默默地将这些字段从私有更改为包范围!
相反,IIRC 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; //Field field:I
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 看到该方法。
所以看起来那里有一些安全功能,但我找不到任何文档。
(因此这篇文章在 CW 中,以防有人知道 0x1000 在类文件中的含义)