La ragione di questo è una combinazione di due istruzioni nel JLS:
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.
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.
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
Quello che trovo curioso è che puoi effettivamente usare l'espressione 'a.arr [0]'. – RealSkeptic
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