2015-09-16 13 views
11

perche il seguente codice:lunghezza della serie di classe privata non è accessibile

class A { 
    B[] arr = new B[10]; 

    private class B {} 
} 


class C { 
    void fun(){ 
     A a = new A(); 
     Object arr = a.arr; 
     Object len = a.arr.length; // !! ERROR 
    } 
} 

Come ho scritto in codice. a.arr.length; sta dando errore.

In realtà capisco perché sta accadendo. È perché la sottoclasse B è privata. Ma ancora perché sta accadendo. In classe A, la proprietà arr era accessibile, ma perché non è lunga. C'è qualche spiegazione per questo in jls o ovunque.

Voglio solo una spiegazione chiara per questo comportamento. So che le cose private non sono accessibili al di fuori della sua classe. Ma potrebbe essere una matrice pubblica. Non importa di che tipo sia. E se qualcosa è accessibile al di fuori, è necessario accedere anche alle sue proprietà pubbliche. Ma qui non sta succedendo.

Modifica: Ho scoperto che in C# non è nemmeno possibile creare un array di classe privata. In java se non possiamo accedere a nulla, e non possiamo nemmeno sapere la lunghezza della matrice della classe privata, allora a cosa serve creare una matrice di classe privata.

+2

dati privati ​​possono accedere solo tramite il metodo pubblico della stessa classe. Il valore predefinito di "arr" è quindi visibile all'interno di "A", ma "B" è privato, quindi non è così. rimuovere privato da 'B' non mostrerà alcun errore. – Rustam

+0

Quello che trovo curioso è che puoi effettivamente usare l'espressione 'a.arr [0]'. – RealSkeptic

+0

Per quanto riguarda la modifica, ci sono molti usi per un array di una classe privata. Puoi usarlo per scopi interni alla classe che li include. Oppure puoi esporre elementi in esso come valori di ritorno ecc. – RealSkeptic

risposta

2

La ragione di questo è una combinazione di due istruzioni nel JLS:

  1. Item 6.6.1 Determinazione accessibilità:

    un tipo di matrice è accessibile se e solo se il suo tipo elemento è accessibile.

    Ciò significa che se T è privato, T[] è anche considerato privato.

  2. Item 10.7 membri dell'array:

    Il public final campo length, che contiene il numero di componenti della matrice. la lunghezza può essere positiva o pari a zero.

Ricordate che l'accessibilità è determinato a tempo di compilazione in base al tipo di riferimento avete, non sul tipo di oggetto reale!

Ora, passiamo a un esempio un po 'più elaborato per dimostrare cosa significa. Ho aggiunto un toString() e un costruttore a B.

class A { 
    B[] arr = { new B(1), new B(2), new B(3), new B(4) }; 
    B plain = new B(99); 

    private class B { 
     public int i; 
     B(int i) { 
      this.i = i; 
     } 
     @Override 
     public String toString() { 
      return "Hidden class B(" + i + ")"; 
     } 

    } 
} 

Ora, in classe C, usiamo:

A a = new A(); 
Object plain = a.plain; 
String s = plain.toString(); 

Questo è legale, perché a.plain è un campo visibile. s conterrà Hidden class B(99). Ma se si prova:

String s = a.plain.toString(); // Compile error 

Questo non sarà consentito, perché althogh toString() in B è pubblica, B sé è privato, non si ha accesso ai suoi membri, siano essi pubblici o privati.

Nota che non è possibile accedere a i in B nonostante sia pubblico. Se usiamo:

plain.i 

Poi dal i non è un membro del Object, si ottiene un errore di compilazione. E se usiamo:

a.plain.i 

Poi dal a.plain è privato, non è possibile accedere ai suoi membri, come abbiamo già provato.

Quindi ora andiamo a esaminare il problema degli array. Supponiamo che scriviamo:

Object[] objArr = a.arr; 
int len = objArr.length; 

Questo è legale, nonostante il fatto che objArr internamente A.B[]. Abbiamo un riferimento a Object[], Object è pubblico e quindi è Object[]. Ma:

int len = a.arr.length; 

ti dà un errore di compilazione esattamente come abbiamo ottenuto per a.plain.toString(). Anche se length è di per sé pubblico, si accede a esso tramite un riferimento a A.B[]. A.B[] non è accessibile perché A.B non è accessibile. Pertanto, poiché length è membro, non è possibile accedervi. Semplicemente non puoi accedere a nessun membro di un tipo di riferimento che non è visibile a te, secondo la prima regola sopra.

E 'interessante notare che il seguente è legale:

Object firstItem = a.arr[0]; 

possiamo usare l'espressione a.arr[0] perché non è considerato un tentativo di accedere a un membro della matrice. Gli elementi dell'array non sono considerati membri in esso. a.arr[0] è semplicemente un'espressione su un riferimento di matrice che consente di digitare A.B. Non c'è alcun problema con una tale espressione finché non proviamo ad accedere ai membri dell'articolo.

Sommario

  • E 'OK per entrare in possesso di un riferimento a un tipo privato, a condizione che si lanci in una certa supertipo pubblico.
  • È OK ottenere un elemento specifico in un array di un tipo privato. L'indicizzazione dell'array non è considerata "accesso a un membro", è solo un'espressione su un riferimento che ti fornisce un riferimento al suo tipo di membro. Per poter utilizzare, è necessario trasmettere a qualcosa di pubblico.
  • Non è corretto provare ad accedere a un membro con un determinato riferimento a un tipo privato, anche se il membro è pubblico. Ciò include lo length di un array.
  • È possibile accedere a quel membro pubblico tramite un cast a un supertipo se è disponibile in quel supertipo. length è disponibile in Object [] così puoi farcela.
  • Non è possibile accedere a un membro pubblico di un tipo privato che non esiste in un supertipo accessibile.
3

Fate questo:

class A { 
    B[] arr = new B[10]; 

    public int getArrayLength() 
    { 
     return arr.length; 
    } 
    private class B {} 
} 


class C { 
    void fun(){ 
     A a = new A(); 
     Object arr = a.arr; 
     //Object isn't type safe 
     //Object len = a.getArrayLength(); 
     int len = a.getArrayLength(); 
    } 
} 

Secondo JavaDocs

A livello di Stati, è anche possibile utilizzare il modificatore pubblico o senza modificatori (pacchetto-privato), così come con le classi di primo livello e con lo stesso significato. Per i membri, ci sono due ulteriori modificatori di accesso: privati ​​e protetti. Il modificatore privato specifica che è possibile accedere al membro solo nella sua classe. Il modificatore protetto specifica che è possibile accedere al membro solo all'interno del proprio pacchetto (come con package-private) e, inoltre, da una sottoclasse della sua classe in un altro pacchetto.

+1

Il post non è un problema. Non sto cercando una soluzione. Ma una spiegazione. Quello che volevo fare poteva essere fatto in molti modi. Ma la domanda è il comportamento del codice che ho presentato. – afzalex

+0

nel collegamento a JavaDocs è spiegato molto bene perché il tuo array privato non è visibile all'esterno, e se non lo vedi, neanche i suoi metodi sono –

+0

La tua citazione non proviene da JavaDocs, è da Java Tutorials. Ed è solo una descrizione generale dei modificatori di accesso, non spiega perché la lunghezza di una matrice è considerata un membro della sua classe di elementi. – RealSkeptic

1

Sa che la domanda riguarda l'accesso al campo length. Ma, è stato interessante per me trovare che la length può essere determinato da una maggiore-per-loop, non apportando modifiche al privilegi di accesso o l'utilizzo di riflessione:

int length = 0; 
for(Object o : a.arr) { 
    length++; 
} 

dichiarazioni interessanti Poche su array sono stati:

Arrays

Nel linguaggio di programmazione Java, gli array sono oggetti (§4.3.1), sono creata dinamicamente, e possono essere assegnati a variabili di tipo Object (§4.3.2). Tutti i metodi di classe Object possono essere richiamati su un array.

Array Types

lunghezza di un array non è parte del suo tipo.

Problemi correlati