给出下面的代码示例,为什么accessUsingReflection
-> theAnswer.get( outer )
抛出IllegalAccessException
而accessDirectly
打印42正好好?
Exception in thread "main" java.lang.IllegalAccessException: Class Outer$Inner can not access a member of class Outer with modifiers "private"
根据这个SO的答案,我希望它能工作,因为访问确实发生"(…)从一个允许访问它的类"。
import java.lang.reflect.Field;
public class Outer
{
private int theAnswer = 42;
public static class Inner
{
public void accessDirectly( Outer outer )
{
System.out.println( outer.theAnswer );
}
public void accessUsingReflection( Outer outer ) throws NoSuchFieldException,
SecurityException,
IllegalArgumentException,
IllegalAccessException
{
Field theAnswer = Outer.class.getDeclaredField( "theAnswer" );
// Of course, uncommenting the next line will make the access using reflection work.
// field.setAccessible( true );
System.out.println( theAnswer.get( outer ) );
}
}
public static void main( String[] args ) throws NoSuchFieldException,
SecurityException,
IllegalArgumentException,
IllegalAccessException
{
Outer outer = new Outer();
Inner inner = new Inner();
inner.accessDirectly( outer );
inner.accessUsingReflection( outer );
}
}
像这样的"为什么"问题很难回答——"为什么"有很多层次,包括为什么设计师选择这样做?规范的哪一部分允许这样做?底层技术细节是什么?
我会回答最后一个问题,但我不确定这是否是你想要的。
Java运行时(JVM、安全模型等)在很大程度上对内部类一无所知。在很大程度上,这是一个语言问题。
这样做的后果之一是编译器使用了一些隐藏的技巧来允许内部/外部类访问彼此的私有成员,尽管运行时通常不允许这样做。
其中一个技巧是你的accessDirectly
方法实际上并没有直接访问字段。编译器在外部类中添加一个隐藏方法,返回theAnswer
的值。
字段(theAnswer
)仍然是私有的,并且就运行时安全模型而言,不能在所属(外部)类之外访问。
因此,有些事情你可以(表面上)在Java代码中做,而你不能在反射中做,因为它们依赖于编译器中的特殊行为,而这些行为不会在反射库中复制。
你可以在这里阅读更多
您的public static void main( String[] args )
和字段private int theAnswer = 42
在同一个类中,因为accessDirectly
打印42正好好(您可以访问外部类中的字段),但是当您使用反射时,您正在加载对象类Class Outer
,其中字段private int theAnswer = 42
是私有的(无法访问另一个类私有字段)。如果没有field.setAccessible( true )
调用,则抛出异常java.lang.IllegalAccessException
。
在这个例子中,方法是从同一个类调用的,但是你是从内部类public static class Inner
调用的。