2011-12-29 9 views
7

Questa è probabilmente una brutta cosa da fare, come discusso in Can parent and child class in Java have same instance variable?. (Cosa succede se il nome della variabile genitore è cambiato? Quindi non sarà più ombreggiato.) Tuttavia, sono ancora curioso di sapere se le variabili che sono statisticamente/non statiche si oscureranno a vicenda. Da un lato, mi sarei aspettato che fossero lo stesso nome di variabile, quindi sarebbe stato ombreggiato, ma d'altra parte sembra che il compilatore possa distinguere tra i due in base alla staticità.In Java, se una classe figlio ombreggia una variabile padre statica con una variabile figlio di istanza, quale variabile utilizzerà i metodi ereditati?

+1

sento che questa è una cosa importante da considerare e possono aiutare gli altri, in modo da questa domanda è d'uso, ma: ** Avete provato ** –

+4

provarlo è una cosa, ma che può essere compilatore? dipendente. Mi chiedo se c'è una regola definitiva a riguardo nelle specifiche del linguaggio. –

risposta

4

Da The Java Language Specification:

Se il nome di espressione consiste di un singolo Identifier, allora ci devono essere esattamente una dichiarazione visibile denota sia un locale variabile, parametro o campo nell'ambito nel punto in cui il Si verifica l'identificatore. In caso contrario, si verifica un errore in fase di compilazione.

Se la dichiarazione dichiara un campo finale, il significato del nome è il valore di quel campo. Altrimenti, il significato dell'espressione nome è la variabile dichiarata dalla dichiarazione.

Se un metodo in una superclasse fa riferimento a un particolare campo (statico o meno) di quella classe, solo la dichiarazione del campo di quella classe sarà in ambito in quel punto; qualsiasi campo (statico o altro) di sottoclassi non sarà incluso nell'ambito. Pertanto, il metodo utilizzerà sempre il campo della superclasse, anche se una sottoclasse lo eredita e ombreggia il campo.

Questa risposta è completamente riscritta in base alla mia nuova comprensione della domanda. Di seguito la mia prima risposta, tenuta per i posteri.

Da The Java Language Specification:

Una dichiarazione d di un campo, variabile locale, parametro del metodo, costruttore parametro parametro o al gestore delle eccezioni di nome n ombre le dichiarazioni di tutti gli altri campi, locali variabili, metodo parametri, parametri costruttore o parametri gestore eccezioni n che sono nel campo di applicazione nel punto in cui d si verifica in tutto l'ambito di d.

Ciò suggerisce che i compilatori sono obbligati a ombreggiare le variabili padre, indipendentemente dalla staticità.

Si noti che nessuno di questi è rilevante per ereditato dai metodi, che utilizzano sempre le variabili originali indipendentemente dal fatto che una sottoclasse li ombreggia. Sospetto che non sia questo che intendevi chiedere.

+1

Questa è in realtà una risposta a ciò che stavo cercando di chiedere: "nulla di ciò è rilevante per i metodi ereditati, che usano sempre le variabili originali indipendentemente dal fatto che una sottoclasse li ombreggia". –

+0

La specifica del linguaggio dice questo? Se sì, dove? Sto cercando di trovarlo. –

+0

@DougTreadwell Sì, lo fa. Ho modificato la mia risposta. – Taymon

0

Guarda il codice qui sotto. Se si desidera accedere a field da ChildClass, verrà utilizzata la propria variabile membro. Se si desidera accedere allo statico field da SuperClass, è necessario chiamarlo in modo esplicito utilizzando SuperClass.field. È possibile accedere direttamente a `STATIC_FIELD`` poiché non vi è alcuna ambiguità per il compilatore.

public class SuperClass{ 
    static String field = "staticField1"; 
    static String STATIC_FIELD = "staticField2"; 

    //not possible to have a member field in this class -> compile error 
    //String field = "memberField"; is not possible 
    public SuperClass() { 
     System.out.println("field = " + field); 

    } 
    } 
    public class ChildClass extends SuperClass{ 
    String field = "memberField"; 

    public ChildClass() { 
     System.out.println("field = " + field);//access to member field 
     //need to explicitly call SuperClass.field to access the static variable 
     System.out.println("SuperClass.field = " + SuperClass.field); 
     //no need to do this when there is no amibiguity 
     System.out.println("STATIC_FIELD = " + STATIC_FIELD); 
    } 
    } 

Vedi anche 15.11.1 e 15.11.2 in here e 8,3 in here

+0

Capisco l'idea di shadowing, ma la parte importante della mia qusetion è "quale variabile erediterà i metodi usati?". –

6

Come da specifica del linguaggio Java:

Se la classe dichiara un campo con un certo nome, quindi la dichiarazione si dice che quel campo nasconda e tutte le dichiarazioni accessibili dei campi con lo stesso nome in superclassi e superinterfacce della classe.

Un campo nascosto si può accedere utilizzando un nome qualificato (se è statico)

JVM Specification

sezione "Dichiarazioni di campo" si può fare riferimento.

+0

Finora questa è una delle migliori risposte, ma sembra concentrarsi solo sullo shadowing. Non rimuoverei alcuna informazione, ma c'è qualcosa di aggiuntivo nelle specifiche che indicherebbe che i metodi ereditati usano anche i campi del bambino? –

+0

Sembra che tu abbia una risposta per questo da Taymon. – kosa

+0

+1 a questa risposta perché indica che è ancora possibile accedere al campo tramite il nome completo. – Bill

4

, a:

class Parent { 
    static String x="static in parent"; 
    String y="instance in parent"; 
} 
class Child extends Parent { 
    static String y="static in child"; 
    String x="instance in child"; 
    void foo() { 
     System.out.println("x "+x); 
     System.out.println("super.x " + super.x); 
     System.out.println("y "+y); 
     System.out.println("super.y " + super.y); 
    } 
} 
public class Main { 
    public static void main(String[] args) { 
     Parent parent=new Parent(); 
     Child child=new Child(); 
     System.out.println("Parent.x "+Parent.x); 
     System.out.println("parent.x "+Parent.x); 
     System.out.println("parent.y "+parent.y); 
     System.out.println("child.x "+child.x); 
     System.out.println("Child.y "+Child.y); 
     System.out.println("child.y "+child.y); 
     System.out.println("(Parent)child).x "+((Parent)child).x); 
     System.out.println("(Parent)child).y "+((Parent)child).y); 
     child.foo(); 
    } 
} 



Parent.x static in parent 
parent.x static in parent 
parent.y instance in parent 
child.x instance in child 
Child.y static in child 
child.y static in child 
(Parent)child).x static in parent 
(Parent)child).y instance in parent 
x instance in child 
super.x static in parent 
y static in child 
super.y instance in parent 
+1

Pubblica anche l'output, in modo che le persone possano apprendere ciò che fa, sia come commenti in-line sia come output incollato sotto – Bohemian

+0

Capisco l'idea di shadowing, ma la parte importante del mio qusetion è "quale variabile erediterà i metodi usati? ". –

+0

vedere le modifiche –

0
public class Test { 

    public static int MYNUMBER = 5; 

    public Test() { 
    } 
} 

public class TestChild extends Test { 

    public int MYNUMBER = 8; 

    public TestChild() { 
    } 
} 

public class Main { 

    public static void main(String[] args) { 
     TestChild testChild = new TestChild(); 

     // This would print out 8 
     System.out.println("in main test child: " + testChild.MYNUMBER); 

     // This won't even compile if the MYNUMBER variable is overshadowed 
     // If the MYNUMBER variable is not overshadowed it 
     // would compile and 
     // print out 5 
     // If we make MYNUMBER static also on TestChild, 
     // it would compile and print out 8 
     System.out.println("in main TestChild.MYNUMBER " + TestChild.MYNUMBER); 

     // This would print out 5 
     System.out.println(Test.MYNUMBER); 
    } 

} 
+0

Capisco l'idea di shadowing, ma la parte importante del mio qusetion è "quale variabile erediterà i metodi ?". –

+0

I metodi ereditati useranno la variabile statica del genitore. Quindi se aggiungiamo alla classe Test il metodo: public int doSomething() { \t \t return MYNUMBER; \t} doSomething restituirà 5 in ogni momento. – Alex

0

Con il compilatore di Eclipse, i metodi della classe padre continueranno a utilizzare le variabili membro della superclasse, non le variabili ombreggiate della classe figlio, come mostrato di seguito. Questa è solo una versione leggermente modificata della risposta di thinksteep.

class Parent { 
    static String x ="static in parent"; 
    String y="instance in parent"; 

    void bar() { 
     System.out.println("x "+ x); 
     System.out.println("y "+ y); 
    } 
} 

class Child extends Parent { 
    static String y ="static in child"; 
    String x="instance in child"; 

    void foo() { 
     System.out.println("x "+x); 
     System.out.println("super.x " + super.x); 
     System.out.println("y "+y); 
     System.out.println("super.y " + super.y); 
    } 
} 

public class Main { 
    public static void main(String[] args) { 
     Parent parent=new Parent(); 
     Child child=new Child(); 
     System.out.println("Parent.x "+Parent.x); 
     System.out.println("parent.x "+Parent.x); 
     System.out.println("parent.y "+parent.y); 
     System.out.println("child.x "+child.x); 
     System.out.println("Child.y "+Child.y); 
     System.out.println("child.y "+child.y); 
     System.out.println("(Parent)child).x "+((Parent)child).x); 
     System.out.println("(Parent)child).y "+((Parent)child).y); 
     System.out.println("Member variable visibility in parent:"); 
     parent.bar(); 
     System.out.println("Member variable visibility in child:"); 
     child.foo(); 
     System.out.println("Member variable visibility in inherited methods:");   
     child.bar(); 

     System.exit(0); 
} 

/* Output: 
Parent.x static in parent 
parent.x static in parent 
parent.y instance in parent 
child.x instance in child 
Child.y static in child 
child.y static in child 
(Parent)child).x static in parent 
(Parent)child).y instance in parent 
Member variable visibility in parent: 
x static in parent 
y instance in parent 
Member variable visibility in child: 
x instance in child 
super.x static in parent 
y static in child 
super.y instance in parent 
Member variable visibility in parent methods: 
x static in parent 
y instance in parent 
*/ 
Problemi correlati