为什么使用反射访问外部类的私有成员会抛出IllegalAccessException



给出下面的代码示例,为什么accessUsingReflection -> theAnswer.get( outer )抛出IllegalAccessExceptionaccessDirectly打印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调用的。

相关内容

  • 没有找到相关文章

最新更新