2011-12-29 9 views
7

Esto probablemente sea una mala cosa, como se explica en Can parent and child class in Java have same instance variable?. (¿Qué sucede si se cambia el nombre de la variable principal? Entonces ya no se sombreará). Sin embargo, todavía tengo curiosidad de si las variables que son diferentes estáticas/no estáticas se verán una a la otra. Por un lado, esperaría que tengan el mismo nombre de variable, por lo que se verían sombreados, pero, por otro lado, parece que el compilador podría distinguir entre los dos en función de la estática.En Java, si una clase secundaria sombrea una variable primaria estática con una variable hija de instancia, ¿qué variable usarán los métodos heredados?

+1

siento que esto es algo importante tener en cuenta y puede ayudar a los demás, por lo que esta cuestión es de uso, pero: ** ¿Ha probado ** –

+4

probarlo es una cosa, pero que puede ser compilador? dependiente. Me pregunto si hay una regla definitiva sobre esto en la especificación del lenguaje. –

Respuesta

4

De The Java Language Specification:

Si un nombre de expresión consiste en una sola Identificador, entonces no deben ser exactamente una declaración visible que denota una local variable, parámetro o campo en el alcance en el que el Se produce el identificador. De lo contrario, se produce un error en tiempo de compilación.

Si la declaración declara un campo final, el significado del nombre es el valor de ese campo. De lo contrario, el significado del nombre de expresión es la variable declarada por la declaración.

Si un método de una superclase se refiere a un campo particular (estático o de otro modo) de esa clase, única declaración del campo de esa clase será en su alcance en ese punto; cualquier campo (estático o no) de subclases no estará dentro del alcance. Por lo tanto, el método siempre usará el campo de superclase, incluso si una subclase lo hereda y sombrea ese campo.

Esta respuesta está completamente reescrita en base a mi nueva comprensión de la pregunta. A continuación está mi primera respuesta, guardada para la posteridad.

De The Java Language Specification:

Una declaración d de un campo, variable local, parámetro del método, el parámetro parámetro o excepción manejador constructor llamado n sombras las declaraciones de cualquier otro campo, locales variables, método parámetros, parámetros de constructor o parámetros del controlador de excepciones llamado n que están en el alcance en el punto donde d ocurre a través del alcance de d.

Esto sugiere que los compiladores deben sombrear las variables principales, independientemente de la estática.

Tenga en cuenta que nada de esto es relevante para métodos heredados, que siempre usan las variables originales independientemente de si una subclase los sombrea. Sospecho que esto no es lo que querías preguntar.

+1

Esto es en realidad una respuesta a lo que estaba tratando de preguntar: "nada de esto es relevante para los métodos heredados, que siempre usan las variables originales, independientemente de si una subclase las sombrea". –

+0

¿La especificación del lenguaje dice esto? ¿Si es así, donde? Estoy tratando de encontrarlo. –

+0

@DougTreadwell Sí, lo hace. He editado mi respuesta. – Taymon

0

Mira el código a continuación. Si desea acceder al field desde ChildClass, usará su propia variable miembro. Si desea acceder al field estático desde SuperClass, tiene que llamarlo explícitamente usando SuperClass.field. Se puede acceder directamente al `STATIC_FIELD`` ya que no hay ambigüedad para el compilador.

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); 
    } 
    } 

Véase también 15.11.1 y 15.11.2 en here y 8,3 en here

+0

Entiendo la idea de sombreado, pero la parte más importante de mi experiencia es "¿qué variable usarán los métodos heredados?". –

6

De acuerdo con la especificación del lenguaje Java:

Si la clase declara un campo con un nombre determinado, entonces la declaración de ese campo se dice que oculta todas y cada una de las declaraciones accesibles de los campos con el mismo nombre en superclases y superinterfaces de la clase.

Un campo oculto se puede acceder mediante el uso de un nombre completo (si es estática)

JVM Specification

lo puede canalizar la sección "Declaraciones de campo".

+0

Hasta ahora, esta es una de las mejores respuestas, pero parece centrarse solo en el sombreado. No eliminaría ninguna información, pero ¿hay algo adicional en la especificación que indique que los métodos heredados también usan los campos del niño? –

+0

Parece que tienes respuesta para esto de Taymon. – kosa

+0

+1 a esta respuesta porque menciona que todavía puede acceder al campo mediante un nombre completamente calificado. – Bill

4

lo harán:

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

Publique la salida también, para que la gente pueda saber lo que hace, ya sea como comentarios en línea o la salida pegada debajo de – Bohemian

+0

Entiendo la idea de sombreado, pero la parte importante de mi qusetion es "¿qué variable usarán los métodos heredados? ". –

+0

Consulte las ediciones –

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

Entiendo la idea del sombreado, pero la parte más importante de mi qusetion es "qué variable utilizarán los métodos heredados". ? ". –

+0

Los métodos heredados usarán la variable estática del elemento principal. Entonces, si agregamos a la clase Prueba el método: public int doSomething() { \t \t return MYNUMBER; \t} doSomething devolverá 5 en todo momento. – Alex

0

Con el compilador de Eclipse, los métodos de la clase principal seguirán utilizando las variables miembro de la superclase, no las variables sombreadas de la clase secundaria, como se muestra a continuación. Esta es una versión ligeramente modificada de la respuesta de 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 
*/ 
Cuestiones relacionadas