2012-10-23 11 views
8

Non riesco a capire come funziona l'ereditarietà in Java quando sono presenti classi interne. Attualmente sto lavorando a qualcosa in cui una classe figlia ha bisogno di modificare leggermente la funzionalità della classe interna del suo genitore. Di seguito ho trovato un esempio più semplice e analogo.Come funziona l'ereditarietà di Java quando sono coinvolte classi interne

Mi aspettavo che questo codice stampasse "I am a ChildClass.InnerClass", ma invece stampa "I am a ParentClass.InnerClass". Perchè è questo? Inoltre, se cambio l'oggetto obj nel main di tipo ChildClass, l'output cambia in "I am a ChildClass.InnerClass". Perchè è questo?

In generale, qual è il modo consigliato di alterare il comportamento dell'oggetto interno della classe genitrice di un oggetto?

class InnerClassTest { 
    //----------------------------------------------------------------------- 
    // PARENT CLASS 
    class ParentClass { 
     public ParentClass() { 
     x = new InnerClass(); 
     } 

     InnerClass x; 

     class InnerClass { 
     public void speak() { 
      System.out.println("I am a ParentClass.InnerClass"); 
     } 
     } 
    } 

    //----------------------------------------------------------------------- 
    // CHILD CLASS 
    class ChildClass extends ParentClass { 
     public ChildClass() { 
     x = new InnerClass(); 
     } 

     InnerClass x; 

     class InnerClass extends ParentClass.InnerClass { 
     public void speak() { 
      System.out.println("I am a ChildClass.InnerClass"); 
     } 
     } 
    } 

    //----------------------------------------------------------------------- 
    // MAIN 
    public static void main(String[] args) { 
     ParentClass obj = (new InnerClassTest()).new ChildClass(); 
     obj.x.speak(); 
    } 
} 

risposta

6

Le variabili non sono "sovrascritte" come lo sono i metodi.

Nella vostra chiamata, ci si aspetta che x sia Child ma non è perché x è una variabile, non un metodo.

Ma attenzione: Il tuo tipo di riferimento è ParentClass così obj.x punti all'attributo 's il ParentClassInnerClass anche se la vera istanza dietro parentClass è un ChildClass!

Per visualizzare la tua frase previsto, è necessario modificare il riferimento di tipo a ChildClass:

public static void main(String[] args) { 
     ChildClass obj = (new InnerClassTest()).new ChildClass(); 
     obj.x.speak(); 
} 

Per capire meglio il concetto, cercare di definire un metodo in entrambe le ParentClass e ChildClass classi:

public InnerClass getInnerClass(){ 
    return x; 
} 

e rendere privato x.

in modo da applicare il "concetto di override".

La chiamata finale sarebbe in questo caso:

ParentClass obj = (new InnerClassTest()).new ChildClass(); 
obj.getInnerClass().speak(); 

per modificare il comportamento delle classi interne, pensare a Template metodo modello o meglio: Strategia modello (dal più rispettosa DIP)

3

Rimuovere il ridichiarazione

InnerClass x; 

fr om la classe bambino. Quindi, si avrà un solo x e verrà riassegnato nel costruttore della classe figlio. Il che significa uno x (riferendosi all'oggetto creato in child ctor).

Nasconde quello nella classe padre. Questo è il motivo per cui si finisce per avere due campi, riferendosi a due oggetti diversi.E a causa di statico (a tempo di compilazione o all'inizio) vincolante in caso di variabili,

ParentClass obj; 
//obj.x means the x in parent 

e

ChildClass obj; 
//obj.x means the x in child 
+0

'ParentClass obj; //obj.x significa la x in child' ?? intendevi l'obj ChildClass; – exexzian

+0

@sansix: esattamente. Grazie per la modifica. –

+0

+1 per la soluzione – exexzian

1

In generale, qual è il modo consigliato di alterare il comportamento di un oggetto di oggetto interno della classe genitore?

Si consiglia di utilizzare un design meno contorto per iniziare. Una classe figlio dovrebbe modificare il comportamento del suo genitore sovrascrivendo i suoi metodi, quindi aggiungerei semplicemente un metodo factory newInnerClass() per sovrascrivere la creazione di questa dipendenza e gestire questo oggetto nella parte superiore della gerarchia delle classi.

Questo sarebbe più flessibile di quello che si propone, perché newInnerClass() potrebbe creare un'istanza di una classe che è definita ovunque fintanto che ha l'interfaccia giusta.

Problemi correlati