2011-02-26 98 views
11

我的印象是私有的非靜態變量只能通過變量駐留在對象上的方法訪問,但事實並非如此。有人能解釋爲什麼以下編譯和運行的原因嗎?訪問私有變量的Java靜態方法

public class Sandbox { 
    private String _privateString = "unmodified"; 
    public static void setPrivateString(String str, Sandbox s) { 
     s._privateString = str; 
    } 
    public String toString() 
    { 
     return _privateString; 
    } 

    public static void main(String[] args) { 
     Sandbox s = new Sandbox(); 
     setPrivateString("modified", s); 
     System.out.println(s); 
    } 
} 

輸出:

modified 

編輯:同樣是在C#真。

+0

您可以直接從'main()'修改'_privateString'作爲它在同一個類中。 – 2011-02-26 19:15:45

回答

17

類A的私有成員變量可以被訪問(即讀/寫)任何類的方法(靜態或非靜態),所以在你的例子中,因爲改變字符串的方法是一個方法該成員屬於同一個類,它被授予訪問該變量的權限。

原因是因爲一個類被認爲是一個自包含的邏輯體(即一個特定的實現),因此隱私被包含在一個類中是合理的,儘管沒有理由從該訪問中排除靜態方法正確,因爲它們也是類提供的具體實現的一部分。

+1

因此,類的任何實例都可以訪問該類的所有其他實例的所有私有變量?正確! – 2011-02-26 19:17:08

+0

起初可能看起來很奇怪,但當你考慮一個類作爲一個單一的實現時,它是有意義的。 – davin 2011-02-26 19:19:02

+0

@ T.K。例如,'public void changeOther(String changeTo,Sandbox s){s._privateString = changeTo; }'可以完全在另一個實例上執行:'s1.changeOther(「blah」,s2);' – davin 2011-02-26 19:21:37

2

規則很簡單。類的成員方法可以訪問和修改相同類的私有成員,而不管它們的可見性修飾符如何。

3

正如其他一些文章中提到的,Java的可見性系統是基於類的,而不是基於對象的。

請注意,這是在編譯器中使用的:當您有嵌套類並訪問外部類的專用字段時,會生成一個公共靜態方法以允許訪問。它通常被命名爲「access $ 0」等。您可以通過使用這些合成方法創建一個違反封裝而不使用Reflection API的字節碼。您也可以從Reflection API訪問它們,而無需訪問私有成員。許多瘋狂的事情可以做...

如果沒有這樣的可見性系統,編譯器可能需要編譯它elsehow。

...... Hoewver,最終程序員通常不需要知道這個細節。 IDE在代碼完成中不包含合成方法,我希望編譯器(除了Jasmin)不允許您使用它。所以如果你不生成字節碼,也不使用Reflection API,並且你在堆棧跟蹤中忽略了這些方法,那麼你可能不需要知道這個細節。

3

您似乎很困惑visibilityscope。實例變量在實例的範圍內,因此它們不能直接在靜態方法中訪問,而只能使用實例引用限定符:s._privateString

但是,這並不意味着對於同一類中的靜態方法,實例變量不是可見,因爲private表示類內部可見(對於具有任何作用域的任何成員)。