2016-06-28 14 views
4

給出下面的代碼示例,爲什麼accessUsingReflection - >theAnswer.get(outer)會拋出IllegalAccessExceptionaccessDirectly只打印42?爲什麼使用反射拋出IllegalAccessException來訪問外部類的私有成員?

Exception in thread "main" java.lang.IllegalAccessException: Class Outer$Inner can not access a member of class Outer with modifiers "private" 

this SO answer,我會「從被允許訪問一個類(......)」期望它的工作作爲訪問確實會發生。

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); 
    } 
} 

回答

2

「爲什麼」這樣的問題很難回答 - 有很多層次的「爲什麼」,包括爲什麼設計師選擇這樣做?規範允許的部分是什麼?底層技術細節是什麼?

我會回答這些的最後一個,但我不確定這是你之後。

Java運行時(JVM,安全模型等)很大程度上不了解內部類。他們大部分是語言問題。

這樣做的後果之一是編譯器使用一些隱藏技巧來允許內部/外部類訪問彼此的私有成員,即使運行時通常不允許它。

這些技巧之一是,你的accessDirectly方法實際上並不直接訪問該字段。編譯器向隱藏的方法添加一個返回值爲theAnswer的外部類。

該字段(theAnswer)仍然是私有的,就運行時安全模型而言,不能在擁有(外部)類之外訪問。

因此,您可以(看似)在Java代碼中執行某些操作,因爲它們依賴於編譯器中未在反射庫中複製的特殊行爲,所以無法使用反射。

你可以閱讀更多here

+0

你是對的 - 我意識到這個問題可能存在技術和概念方面的事實。但你的全面答案正是我所追求的。 –

0

public static void main(String[] args)和現場private int theAnswer = 42在同一個班,因爲這個事實accessDirectly打印42就好了(你有機會到現場外類),但是當你使用反射,您正在加載對象ClassClass Outer其中字段private int theAnswer = 42是私有的(不能訪問另一個類私有字段)。如果沒有field.setAccessible(true)呼叫,則拋出異常java.lang.IllegalAccessException

this示例方法是從同一個類調用,但是您從內部類public static class Inner調用它。

+1

但直接訪問'theAnswer'不會對在我的'main'方法聲明同一個類發生 - 它從內部類中發生。 –

+0

是的,當您嘗試直接從內部類訪問時,您可以訪問「外部」類中的私有字段。 – mrserfr

相關問題