2015-05-02 19 views
22

Ho codice che assomiglia a questo:Perché Java non mi consente di accedere al metodo privato tramite il metodo della stessa classe?

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

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

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

E IntelliJ mi dice che "uno() ha accesso privato in A", ma hey, perché non riesco a chiamare il membro privato della stessa classe?

+14

'T' è una certa classe che estende' A' ma potrebbe non essere una 'A' –

+0

perché è protetto! così semplice. è l'esence di OO. ecco perché sull'oggetto usiamo i metodi per restituire una variabile invece di accedervi direttamente –

+7

[Dalla bocca del cavallo] (https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html). I bambini di una classe non possono accedere ai metodi privati ​​dei loro genitori perché ... è così che è stato progettato il linguaggio. – snickers10m

risposta

18

private i membri possono accedere solo all'interno della classe in cui ware dichiarate. Quindi, se avete classe

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()` 
    } 
} 

Come vedete non c'è permesso di accedere membro privato da classe derivata anche se siamo di classe all'interno in cui è stato dichiarato a questo utente.

Possibile ragione di questo è che i membri privati ​​non sono ereditate all'interfaccia di classe derivata (che è una specie di scopo della private modificatore di visibilità). A causa di ciò in tali classi è possibile ridichiarare questi membri qualsiasi autore modo vuole, per esempio, qualcuno potrebbe creare di classe come questo:

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

Quindi, come potete vedere, è possibile che chiamando y.method() si sta cercando di accesso method dichiarato nella classe Y, ma non è possibile accedervi dalla classe X (a causa dell'incapsulamento). E questo è il compilatore di scenari ipotizza perché i campi e i metodi privati ​​non sono polimorfi.

Per evitare questa confusione è necessario dichiarare esplicitamente che si vuole invocare membro privato da classe corrente X utilizzando colata

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

Stessa cosa accade per <T extends A>. Dal T può essere qualsiasi sottoclasse di A il compilatore non consentirà l'accesso ai suoi membri privati. Quindi sarà necessario lanciare di nuovo 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

Questo errore di compilazione è stato introdotto in Java 7 come da http://www.oracle.com/technetwork/java/javase/compatibility-417013.html:

Descrizione: In JDK 5.0 e JDK 6, javac consentito erroneamente l'accesso ai membri privati ​​di tipo-variabili. Questo è sbagliato, poiché la JLS, Java SE 7 Edition, sezione 4.4, afferma che i membri di una variabile di tipo sono i membri di un tipo di intersezione i cui componenti sono i limiti della variabile di tipo (i tipi di intersezione sono definiti nella sezione 4.9): e tipi intersezione non ereditano soci privati ​​dai loro componenti

Il tipo di T non può essere A. Può essere di tipo B ovvero una sottoclasse di A. In questo caso, l'accesso al metodo one()one() non è conforme alla regola di ereditarietà che indica che una sottoclasse (ovvero la classe B) non eredita i membri private della relativa classe padre (ovvero la classe A).

+0

Okey, l'ho appena controllato con i soliti tipi, senza generici, e funziona allo stesso modo. Ma ancora non capisco perché? Sappiamo che abbiamo un sottotipo di classe A, quindi perché non possiamo accedere ai membri, che sono privati ​​in A, sulla variabile della sottoclasse? Alla fine cercheremo di accedervi dalla classe A, non infrangeremo alcuna regola di ereditarietà/incapsulamento. – saroff

4

perché non riesco a chiamare il membro privato della stessa classe?

Perché si prova a chiamare il metodo privato da T che può essere derivato da A. Se si aggiunge un cast di A nuovo che funzionerà:

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