2015-05-02 36 views
22

我有代碼看起來像這樣:爲什麼Java不允許我通過同一類的方法訪問私有方法?

public class A<T extends A> { 
    private T one() { return (T) this;} 

    protected T two() { return (T) this;} 

    protected void three() { two().one(); } 
} 

和IntelliJ告訴我,「一個()有私接一個」,但是,嘿,我爲什麼不能調用同一類的私有成員?

+14

'T'是一些類延伸'A',但可能不是一個'A' –

+0

,因爲它是受保護的!那很簡單。它是面向對象的本質。那就是爲什麼我們使用get方法返回一個變量而不是直接訪問它的對象 –

+7

[從馬的嘴裏](https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html)。一個班級的孩子不能訪問父母的私人方法,因爲......這就是語言的設計。 – snickers10m

回答

18

private成員只能在其所潔具聲明的類進行訪問。所以,如果你有類

class X{ 
    private int field = 1; 
    private void method(){} 
    void foo(X x){ 
     x.field = 2; 
     x.method(); // this is OK, because we are accessing members from instance of X 
        // via reference of class X (which is same class as this one) 
    } 

    void bar(Y y){// = lets assume that Y extends X 
     y.field = 3; 
     y.method(); // ERROR: we can't access `method()` 
    } 
} 

正如你看到的,我們不能從派生類訪問私有成員,即使我們在此成員被宣佈內部類。

此問題的可能原因是,私有成員不繼承到派生類(這是一種private可見性修飾符的全部目的)的接口。因爲,在這些類的就可以重新聲明這些成員的任何方式作者希望,比如有人可能會這樣一個創建類:

class Y extends X{ 
    private String field = "foo"; 
    private String method(){ 
     return "bar"; 
    } 
} 

所以你看它有可能通過調用y.method()你想訪問methodY類中聲明,但是你沒有從X類(由於封裝)訪問它。這是情景編譯器假定因爲字段和私有方法並不多態

要通過鑄造

void bar(Y y){ 
    ((X)y).method(); 
} 

同樣的事情發生了<T extends A>避免這種混亂,你需要明確指出,要從當前的類X調用私有成員。由於T可以是A的任何子類,因此編譯器將不允許訪問其私有成員。所以,你需要將它轉換回A

class A<T extends A> { 
    private T one() { return (T) this;} 

    protected T two() { return (T) this;} 

    protected void three() { ((A)two()).one(); } 
} 
12

此編譯器錯誤Java 7中被引入作爲每http://www.oracle.com/technetwork/java/javase/compatibility-417013.html

描述:在JDK 5.0和JDK 6,javac的錯誤地允許訪問類型變量的私有成員。這是錯誤的,因爲JLS,爪哇SE 7版,第4.4節,指出一個類型變量的成員的交叉類型,它們的組成部分是類型變量界限(交集類型在第4.9節中定義)的成員 - 和交叉點類型不從它們的組件

類型的T可能並不A繼承私有成員。它可以是類型B,它是A的子類。在這種情況下,訪問private方法one()不符合繼承規則,說一個子類(即B類)沒有繼承父類的private成員(即A類)。

+0

Okey,我只是用普通的類型檢查它,沒有泛型,它的工作方式也是一樣的。但我仍然不明白爲什麼?我們知道,我們有一個A類的子類型,那麼爲什麼我們不能訪問A類中的私有成員的子類變量?我們最終試圖從A類訪問它們,我們不打破任何繼承/封裝規則。 – saroff

4

爲什麼我不能把同一類的私有成員?

因爲您嘗試調用T的私有方法,可以從A派生。如果添加強制轉換爲A後會正常工作:

protected void three() { ((A)two()).one(); } 
相關問題