2013-03-09 10 views
8

Ho una classe astratta che dovrebbe implementare un campo pubblico, questo campo è un'interfaccia o un'altra classe astratta.Sovrascrivi campi classe Java astratti

qualcosa di simile:

public abstract class GenericContainer { 
    public GenericChild child; 
} 

public abstract class GenericChild { 
    public int prop1=1; 
} 

public abstract class SpecialChild extend GenericChild { 
    public int prop1=2; 
} 

Ora ho un altro contenitore classe specializzata:

public abstract class SpecialContainer extends GenericContainer { 
    public SpecialChild child=new SpecialChild(); //PAY ATTENTION HERE! 
} 

Java mi permettono di compilare questo, e immagino che il campo child in SpecialContainer sta sovraccaricando automaticamente il campo child dello GenericContainer ... Le domande sono: Ho ragione su questo? Accadrà il "sovraccarico" automatico del bambino?

E, ancora più importante domanda, se ho un'altra classe in questo modo:

public class ExternalClass { 
    public GenericContainer container=new SpecialContainer(); 
    public int test() { 
     return container.child.prop1 
    } 
} 

test() torneranno 1 o 2? intendo il campo del contenitore GenericContainer che cosa chiamerà prop1, il generico o il speciale? E se il prop1 speciale fosse dichiarato come String (sì, java mi permette di compilare anche in questo caso)?

Grazie!

+4

campi No. non vengono sovrascritte, solo metodi fanno. –

+0

Quindi se in "SpecialChild" ho un metodo che usa prop1, cosa otterrà alla prima chiamata? 1 o 2? Ho provato e rimosso prop1 da SpecialChild mi permetterà di scrivere un metodo in SpecialChild che usa prop1 anche se questo è definito solo in GenericChild ... Quindi penso che un tipo di sovraccarico accade ... – Alex

+4

potresti sempre provare _running it_ . –

risposta

8

Non è prevalente nulla, si sta solo nascondendo il campo originale alla portata classe corrente. Se si utilizza una variabile con il sottotipo, sarà comunque possibile accedere alla proprietà originale. Esempio:

abstract class GenericContainer { 
    public GenericChild child;  
} 

abstract class GenericChild { 
    public int prop1=1 ; 
} 

class SpecialChild extends GenericChild { 
    public int prop1=2; 
} 

class SpecialContainer extends GenericContainer { 
    public SpecialChild child; 
} 

public class Main { 

    public static void main(String ... args) { 

     GenericContainer container = new SpecialContainer(); 
     container.child = new SpecialChild(); 

     System.out.println(container.child.prop1); 

     SpecialChild child = (SpecialChild) container.child;   
     System.out.println(child.prop1); 
    } 

} 

Questo stampa 1 e poi 2.

Da SpecialChild si sarebbe anche in grado di salire di un livello utilizzando super:

class SpecialChild extends GenericChild { 
    public int prop1=2; 

    public int getOriginalProp1() { 
     return super.prop1; 
    } 

} 
+1

+1 per esempi. –

2

Per quanto riguarda

.... e immagino che il campo "bambino" in SpecialContainer sta sovraccaricando automaticamente il campo 'figlio' del GenericContainer ...

No. I campi don essere sovrascritto, solo i metodi lo fanno.

Questo è uno dei motivi per cui l'uso dei metodi getter e setter (sovrascrivibili) è preferito per l'accesso diretto ai campi. I tuoi campi dovrebbero essere quasi tutti privati.

Per quanto riguarda la progettazione, non è necessario che la classe SpecialContainer abbia un campo SpecialChild, ma l'oggetto SpecialChild deve essere inserito nel campo GenericChild.

1

Java mi permettono di compilare questo, e immagino che il campo "bambino" in SpecialContainer sta sovraccaricando automaticamente il campo 'figlio' del GenericContainer ...

In primo luogo, ereditarietà non si applica alle variabili. I campi (variabili Insatnce) non sono sovrascritti nella sottoclasse. Sono visibili solo nella sottoclasse se sono contrassegnati con public, protected or default.

13

In Java, i membri/gli attributi dati non sono polimorfici. Sovraccarico significa che un campo avrà un valore diverso a seconda della classe a cui è stato effettuato l'accesso. Il campo nella sottoclasse sarà nasconde il campo nella super classe, ma entrambi esistono. I campi vengono richiamati in base ai tipi di riferimento, mentre i metodi vengono utilizzati dell'oggetto reale. Puoi provarlo da solo.

si chiama, nascondere/shadowing variabile, per maggiori dettagli guardano here

+2

Grazie, questa è la risposta che rende le cose più chiare! – Alex

1

Per rispondere alla tua domanda si mantiene entrambi i casi . E a seconda di come ti riferisci al contenitore (tramite l'abstract o l'impl) determina quale variabile ti stai riferendo.

public class Test { 

    public abstract class Container{ 
     public Generic gen = new Generic(); 
    } 

    public class ContainerImpl extends Container{ 
     public GenericImpl gen = new GenericImpl(); 
    } 

    public class Generic{ 
     public int prop = 0; 
    } 

    public class GenericImpl extends Generic{ 
     public int prop = 1; 
    } 

    public Test(){ 
     Container c = new ContainerImpl(); 
     System.out.println(c.gen.prop); // Outputs "0" 
     System.out.println(((ContainerImpl)c).gen.prop); // Output "1" 
    } 

    public static void main(String[] args) { 
     new Test(); 
    } 

} 

La domanda più importante è, perché dovresti progettare qualcosa di simile? Presumo che tu stia chiedendo da una prospettiva teorica.

I miei 2 centesimi, questo non è un gran bel design OO. Sarebbe meglio rendere private le variabili pubbliche e assegnare i loro valori attraverso un costruttore o un setter di proprietà. Così com'è, porterà a risultati inaspettati nel codice.

1

Perché nessuno sta osservando quel programma getterà NullPointerException.
sottoclasse field con lo stesso nome nasconderà la classe field di super classe. Non c'è overriding con field. L'override è possibile solo con i metodi.

codice originale per Autore:

public abstract class GenericContainer { 
    public GenericChild child; 
} 

public abstract class GenericChild { 
    public int prop1=1; 
} 

public abstract class SpecialChild extend GenericChild { 
    public int prop1=2; 
} 

public abstract class SpecialContainer extends GenericContainer { 
    public SpecialChild child=new SpecialChild(); //PAY ATTENTION HERE! 
} 

public class ExternalClass { 
    public GenericContainer container=new SpecialContainer(); 
    public int test() { 
     return container.child.prop1 
    } 
}