Java 为什么使用反射访问外部类的私有成员会引发IllegalAccessException?
给出下面的代码示例,为什么Java 为什么使用反射访问外部类的私有成员会引发IllegalAccessException?,java,reflection,Java,Reflection,给出下面的代码示例,为什么accessUsingReflection->answer.get(outer)抛出一个IllegalAccessException,而accessDirectly打印得很好 Exception in thread "main" java.lang.IllegalAccessException: Class Outer$Inner can not access a member of class Outer with modifiers "private" 根据,我希
accessUsingReflection
->answer.get(outer)
抛出一个IllegalAccessException
,而accessDirectly
打印得很好
Exception in thread "main" java.lang.IllegalAccessException: Class Outer$Inner can not access a member of class Outer with modifiers "private"
根据,我希望它能够工作,因为访问确实发生在允许访问它的类中
您的
public static void main(String[]args)
和fieldprivate int theAnswer=42
在同一个类中,因为事实上accessDirectly
可以很好地打印42(您可以访问外部类中的字段),但是当您使用反射时,您正在加载对象Class-Outer
,其中字段private-int-theAnswer=42
为private(无法访问另一个Class-private字段)。如果没有field.setAccessible(true)
调用,则抛出异常java.lang.IllegalAccessException
在示例中,方法是从同一个类调用的,但您是从内部类调用它公共静态类内部
“为什么”这样的问题很难回答-有很多层“为什么”,包括设计者为什么选择这样做?规范的哪一部分允许这样做?潜在的技术细节是什么
我会回答最后一个问题,但我不确定这是否是你想要的
Java运行时(JVM、安全模型等)基本上不知道内部类。它们在很大程度上是一个语言问题
这样做的后果之一是编译器使用一些隐藏的技巧来允许内部/外部类访问彼此的私有成员,即使运行时通常不允许这样做
其中一个技巧是,accessDirectly
方法实际上不是直接访问字段。编译器将一个隐藏方法添加到外部类中,该类返回answer的值
字段(theAnswer
)仍然是私有的,并且就运行时安全模型而言,不能在所属(外部)类之外访问
因此,在Java代码中可以(似乎)做一些反射无法做的事情,因为它们依赖于编译器中没有在反射库中复制的特殊行为
您可以阅读更多,但是直接访问
答案
不会发生在声明我的main
方法的同一个类上-它发生在内部类中。是的,当您尝试直接从内部
类访问时,您可以访问外部
类中的私有字段。您是对的-我知道这个问题可能有技术和概念方面的问题。但你全面的回答正是我想要的。
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 );
}
}