variable usar otra modificadores metodos metodo llamar estaticos ejemplos cuando clases clase atributos atributo atomicas acceso java inheritance override

usar - modificadores de acceso java



¿Hay alguna manera de anular las variables de clase en Java? (15)

¿Por qué querría anular las variables cuando podría reasignarlas fácilmente en las subclases?

Sigo este patrón para trabajar en el diseño del lenguaje. Supongamos un caso en el que tenga una clase de servicio de gran peso en su marco que necesite utilizar en diferentes sabores en múltiples aplicaciones derivadas. En ese caso, la mejor forma de configurar la lógica de superclase es mediante la reasignación de sus variables "definitorias".

public interface ExtensibleService{ void init(); } public class WeightyLogicService implements ExtensibleService{ private String directoryPath="c:/hello"; public void doLogic(){ //never forget to call init() before invocation or build safeguards init(); //some logic goes here } public void init(){} } public class WeightyLogicService_myAdaptation extends WeightyLogicService { @Override public void init(){ directoryPath="c:/my_hello"; } }

class Dad { protected static String me = "dad"; public void printMe() { System.out.println(me); } } class Son extends Dad { protected static String me = "son"; } public void doIt() { new Son().printMe(); }

La función do Imprimirá "papá". ¿Hay alguna manera de hacerlo imprimir "hijo"?


Aunque es cierto que las variables de clase solo se pueden ocultar en subclases, y no se pueden anular, aún es posible hacer lo que se desee sin anular printMe () en subclases, y el reflejo es tu amigo. En el código a continuación, omito el manejo de excepciones para mayor claridad. Tenga en cuenta que declararme como protected no parece tener mucho sentido en este contexto, ya que se ocultará en subclases ...

class Dad { static String me = "dad"; public void printMe () { java.lang.reflect.Field field = this.getClass ().getDeclaredField ("me"); System.out.println (field.get (null)); } }


De hecho, imprime ''papá'', ya que el campo no se reemplaza, sino que se oculta. Hay tres enfoques para hacer que se imprima ''hijo'':

Enfoque 1: anular PrintMe

class Dad { protected static String me = "dad"; public void printMe() { System.out.println(me); } } class Son extends Dad { protected static String me = "son"; @override public void printMe() { System.out.println(me); } } public void doIt() { new Son().printMe(); }

Método 2: no oculte el campo e inícielo en el constructor

class Dad { protected static String me = "dad"; public void printMe() { System.out.println(me); } } class Son extends Dad { public Son() { me = "son"; } } public void doIt() { new Son().printMe(); }

Método 3: use el valor estático para inicializar un campo en el constructor

class Dad { private static String meInit = "Dad"; protected String me; public Dad() { me = meInit; } public void printMe() { System.out.println(me); } } class Son extends Dad { private static String meInit = "son"; public Son() { me = meInit; } } public void doIt() { new Son().printMe(); }


En resumen, no, no hay forma de anular una variable de clase.

No anula las variables de clase en Java, las oculta. La anulación es, por ejemplo, métodos. Ocultar es diferente de anular.

En el ejemplo que has dado, al declarar la variable de clase con el nombre "yo" en la clase Hijo, ocultas la variable de clase que habría heredado de su superclase Papá con el mismo nombre "yo". Ocultar una variable de esta manera no afecta el valor de la variable de clase ''yo'' en la superclase Papá.

Para la segunda parte de su pregunta, sobre cómo imprimir "hijo", establecería el valor a través del constructor. Aunque el código a continuación se aparta de tu pregunta original bastante, lo escribiría algo como esto;

public class Person { private String name; public Person(String name) { this.name = name; } public void printName() { System.out.println(name); } }

El JLS brinda muchos más detalles sobre la ocultación en la sección 8.3 - Declaraciones de campo


Esto parece un defecto de diseño.

Elimine la palabra clave estática y configure la variable, por ejemplo, en el constructor. De esta forma, Son solo establece la variable a un valor diferente en su constructor.


No puede anular variables en una clase. Puede anular solo los métodos. Debe mantener las variables privadas, de lo contrario, puede tener muchos problemas.


No. Las variables de clase (también aplicables a las variables de instancia) no presentan una función de anulación en Java ya que las variables de clase se invocan en función del tipo de objeto llamante. Se agregó una clase más (Humana) en la jerarquía para hacerlo más claro. Entonces ahora tenemos

Hijo extiende a papá extiende humano

En el código siguiente, tratamos de iterar sobre una matriz de objetos Humanos, Papá e Hijo, pero imprime los valores de la Clase humana en todos los casos, ya que el tipo de objeto que llama es Humano.

class Human { static String me = "human"; public void printMe() { System.out.println(me); } } class Dad extends Human { static String me = "dad"; } class Son extends Dad { static String me = "son"; } public class ClassVariables { public static void main(String[] abc) { Human[] humans = new Human[3]; humans[0] = new Human(); humans[1] = new Dad(); humans[2] = new Son(); for(Human human: humans) { System.out.println(human.me); // prints human for all objects } } }

Se imprimirá

  • humano
  • humano
  • humano

Por lo tanto, no se anulan las variables de Clase.

Si deseamos acceder a la variable de clase del objeto real a partir de una variable de referencia de su clase padre, tenemos que indicarlo explícitamente al compilador al convertir la referencia padre (objeto humano) a su tipo.

System.out.println(((Dad)humans[1]).me); // prints dad System.out.println(((Son)humans[2]).me); // prints son

Se imprimirá

  • papá
  • hijo

Sobre cómo parte de esta pregunta: - Como ya se sugirió anular el método printMe () en la clase Son, luego al llamar

Son().printMe();

La variable de clase del padre "yo" estará oculta porque la declaración más cercana (del método de la clase Son printme ()) del "yo" (en la clase Son) obtendrá la precedencia.


Por supuesto, el uso de atributos privados y getters y setters sería lo más recomendable, pero probé lo siguiente, y funciona ... Ver el comentario en el código

class Dad { protected static String me = "dad"; public void printMe() { System.out.println(me); } } class Son extends Dad { protected static String me = "son"; /* Adding Method printMe() to this class, outputs son even though Attribute me from class Dad can apparently not be overridden */ public void printMe() { System.out.println(me); } } class Tester { public static void main(String[] arg) { new Son().printMe(); } }

Entonces ... ¿acabo de redefinir las reglas de la herencia o puse a Oracle en una situación complicada? Para mí, String me protegido está claramente anulado, como puede ver al ejecutar este programa. Además, no tiene ningún sentido para mí por qué los atributos no deberían ser reemplazables.


Puede crear un getter y luego anular ese getter. Es particularmente útil si la variable que está anulando es una subclase de sí misma. Imagine que su súper clase tiene un miembro de Object , pero en su subclase esto ahora está más definido como un Integer .

class Dad { private static final String me = "dad"; protected String getMe() { return me; } public void printMe() { System.out.println(getMe()); } } class Son extends Dad { private static final String me = "son"; @Override protected String getMe() { return me; } } public void doIt() { new Son().printMe(); //Prints "son" }


Sí, simplemente anule el método printMe() :

class Son extends Dad { public static final String me = "son"; @Override public void printMe() { System.out.println(me); } }


Sí. Pero a medida que se trata de la variable, se sobrescribe (dando un nuevo valor a la variable. Dar nueva definición a la función es Anular). Just don''t declare the variable but initialize (change) in the constructor or static block.

El valor se verá reflejado cuando se use en los bloques de la clase para padres

si la variable es estática, cambie el valor durante la inicialización con bloque estático,

class Son extends Dad { static { me = ''son''; } }

o bien cambie en constructor.

También puede cambiar el valor más tarde en cualquier bloque. Se verá reflejado en super clase


Si va a anularlo, no veo una razón válida para mantener esto estático. Sugeriría el uso de la abstracción (ver código de ejemplo). :

public interface Person { public abstract String getName(); //this will be different for each person, so no need to make it concrete public abstract void setName(String name); }

Ahora podemos agregar al papá:

public class Dad implements Person { private String name; public Dad(String name) { setName(name); } @Override public final String getName() { return name; } @Override public final void setName(String name) { this.name = name; } }

el hijo:

public class Son implements Person { private String name; public Son(String name) { setName(name); } @Override public final String getName() { return name; } @Override public final void setName(String name) { this.name = name; } }

y papá conoció a una buena dama:

public class StepMom implements Person { private String name; public StepMom(String name) { setName(name); } @Override public final String getName() { return name; } @Override public final void setName(String name) { this.name = name; } }

Parece que tenemos una familia, digamos al mundo sus nombres:

public class ConsoleGUI { public static void main(String[] args) { List<Person> family = new ArrayList<Person>(); family.add(new Son("Tommy")); family.add(new StepMom("Nancy")); family.add(new Dad("Dad")); for (Person person : family) { //using the getName vs printName lets the caller, in this case the //ConsoleGUI determine versus being forced to output through the console. System.out.print(person.getName() + " "); System.err.print(person.getName() + " "); JOptionPane.showMessageDialog(null, person.getName()); } }

}

Salida de System.out: Tommy Nancy Dad
System.err es el mismo que el anterior (solo tiene letra roja)
Salida JOption:
Tommy entonces
Nancy entonces
Papá


solo sobrescribiendo printMe() :

class Son extends Dad { public void printMe() { System.out.println("son"); } }

la referencia a me en el método Dad.printMe apunta implícitamente al campo estático Dad.me , por lo que de una forma u otra estás cambiando lo que printMe hace en Son ...


https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html

Se llama Ocultar campos

Desde el enlace de arriba

Dentro de una clase, un campo que tiene el mismo nombre que un campo en la superclase oculta el campo de la superclase, incluso si sus tipos son diferentes. Dentro de la subclase, el campo en la superclase no puede referenciarse por su nombre simple. En cambio, se debe acceder al campo a través de super, que se trata en la siguiente sección. En términos generales, no recomendamos ocultar campos ya que hace que el código sea difícil de leer.


class Dad { protected static String me = "dad"; public void printMe() { System.out.println(me); } } class Son extends Dad { protected static String _me = me = "son"; } public void doIt() { new Son().printMe(); }

... imprimirá "hijo".