Domanda

Ho osservato che le classi esterne possono accedere alle variabili dell'istanza privata delle classi interne. Com'è possibile? Ecco un codice di esempio che dimostra lo stesso:

class ABC{
    class XYZ{
        private int x=10;
    }

    public static void main(String... args){
        ABC.XYZ xx = new ABC().new XYZ();
        System.out.println("Hello :: "+xx.x); ///Why is this allowed??
    }
}

Perché questo comportamento è consentito?

È stato utile?

Soluzione

La classe interna è solo un modo per separare in modo pulito alcune funzionalità che appartengono davvero alla classe esterna originale. Devono essere utilizzati quando hai 2 requisiti:

  1. Alcune funzionalità nella tua classe esterna sarebbero più chiare se fosse implementata in una classe separata.
  2. Anche se è in una classe separata, la funzionalità è strettamente legata al modo in cui funziona la classe esterna.

Dati questi requisiti, le classi interne hanno pieno accesso alla loro classe esterna. Dato che sono fondamentalmente membri della classe esterna, ha senso che abbiano accesso a metodi e attributi della classe esterna, compresi i privati.

Altri suggerimenti

Se ti piace nascondere i membri privati ??della tua classe interna, puoi definire un'interfaccia con i membri pubblici e creare una classe interna anonima che implementa questa interfaccia. Esempio sotto:

class ABC{
    private interface MyInterface{
         void printInt();
    }

    private static MyInterface mMember = new MyInterface(){
        private int x=10;

        public void printInt(){
            System.out.println(String.valueOf(x));
        }
    };

    public static void main(String... args){
        System.out.println("Hello :: "+mMember.x); ///not allowed
        mMember.printInt(); // allowed
    }
}

La classe interna è (ai fini del controllo di accesso) considerata parte della classe di contenimento. Questo significa pieno accesso a tutti i privati.

Il modo in cui questo è implementato sta usando metodi sintetici protetti da pacchetti: la classe interna sarà compilata in una classe separata nello stesso pacchetto (ABC $ XYZ). La JVM non supporta direttamente questo livello di isolamento, quindi a livello di bytecode ABC $ XYZ avrà metodi protetti dal pacchetto che la classe esterna utilizza per raggiungere i metodi / campi privati.

C'è una risposta corretta che appare su un'altra domanda simile a questa: Perché è possibile accedere al membro privato di una classe nidificata con i metodi della classe che lo racchiude?

Dice che esiste una definizione di scoping privato su JLS - Determinazione dell'accessibilità :

  

Altrimenti, se il membro o il costruttore viene dichiarato privato, l'accesso è consentito se e solo se si verifica all'interno del corpo della classe di livello superiore (§7.6) che racchiude la dichiarazione del membro o del costruttore.

/ strong>

Un caso d'uso IMHO importante per le classi interne è il modello di fabbrica. La classe che racchiude può preparare un'istanza della classe interna senza restrizioni di accesso e passare l'istanza al mondo esterno, dove verrà onorato l'accesso privato.

In contraddizione con abyx dichiarando la classe statica non cambia le restrizioni di accesso alla classe acclusa, come mostrato di seguito. Anche le restrizioni di accesso tra le classi statiche nella stessa classe chiusa funzionano. Sono stato sorpreso ...

class MyPrivates {
    static class Inner1 { private int test1 = 2; }
    static class Inner2 { private int test2 = new Inner1().test1; }

    public static void main(String[] args) {
        System.out.println("Inner : "+new Inner2().test2);
    }
}

Le restrizioni di accesso vengono effettuate in base alla classe. Non è possibile che un metodo dichiarato in una classe non sia in grado di accedere a tutti i membri dell'istanza / classe. È ovvio che anche le classi interne hanno accesso illimitato ai membri della classe esterna e la classe esterna ha accesso illimitato ai membri della classe interna.

Inserendo una classe all'interno di un'altra classe, la rendi strettamente legata all'implementazione e tutto ciò che fa parte dell'implementazione dovrebbe avere accesso alle altre parti.

La logica dietro le classi interne è che se crei una classe interna in una classe esterna, è perché dovranno condividere alcune cose, e quindi ha senso per loro poter avere più flessibilità di "normale" ; classi hanno.

Se, nel tuo caso, non ha senso che le classi siano in grado di vedere i reciproci meccanismi interni, il che significa sostanzialmente che la classe interna avrebbe potuto semplicemente essere una classe regolare, puoi dichiarare la classe interna come < codice> classe statica XYZ . L'uso di static significa che non condivideranno lo stato (e, ad esempio new ABC (). New XYZ () non funzionerà e dovrai usare nuovo ABC.XYZ () .
Ma, in tal caso, dovresti pensare se XYZ dovrebbe davvero essere una classe interna e che forse merita un suo file. A volte ha senso creare una classe interna statica (ad esempio, se hai bisogno di una piccola classe che implementa un'interfaccia utilizzata dalla tua classe esterna e che non sarà utile altrove). Ma a circa metà del tempo avrebbe dovuto diventare una classe esterna.

Thilo ha aggiunto una buona risposta per la tua prima domanda " Come è possibile? " ;. Vorrei approfondire un po 'la seconda domanda: perché questo comportamento è permesso?

Per cominciare, chiariamo perfettamente che questo comportamento non è consentito solo per le classi interne che per definizione sono tipi nidificati non statici. Questo comportamento è consentito per tutti i tipi nidificati, inclusi enumerazioni e interfacce nidificate che devono essere statiche e non possono avere un'istanza chiusa. Fondamentalmente, il modello è una semplificazione fino alla seguente dichiarazione: il codice nidificato ha pieno accesso al codice che lo racchiude - e viceversa.

Allora, perché allora? Penso che un esempio illustri meglio il punto.

Pensa al tuo corpo e al tuo cervello. Se iniettate eroina nel braccio, il cervello si alza. Se la regione dell'amigdala del tuo cervello vede ciò che crede sia una minaccia per la tua sicurezza personale, ad esempio una vespa, farà girare il tuo corpo al contrario e corre verso le colline senza di te "pensando". due volte al riguardo.

Quindi, il cervello è una parte intrinseca del corpo - e stranamente, anche il contrario. L'uso del controllo dell'accesso tra entità così strettamente correlate perde la loro pretesa di relazione. Se è necessario il controllo dell'accesso, è necessario separare le classi in unità veramente distinte. Fino ad allora, sono la stessa unità. Un esempio guida per ulteriori studi sarebbe quello di esaminare come un Java Iterator di solito è implementato.

L'accesso illimitato dal codice allegato al codice nidificato rende, per la maggior parte, piuttosto inutile aggiungere modificatori di accesso a campi e metodi di tipo nidificato. In questo modo si aggiunge disordine e potrebbe fornire un falso senso di sicurezza per i nuovi arrivati ??del linguaggio di programmazione Java.

La classe interna è considerata come un attributo della classe esterna. Pertanto, indipendentemente dal fatto che la variabile dell'istanza della classe Inner sia privata o meno, la classe Outer può accedere senza problemi proprio come accedere agli altri suoi attributi privati ??(variabili).

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}

Poiché il tuo metodo main () è nella classe ABC , che può accedere alla propria classe interna.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top