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)
和field
private 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 );
   }
}