java polymorphism

¿Se aplica el polimorfismo en los atributos de clase en Java?



polymorphism (8)

Sé que el uso común del polimorfismo en OOP ocurre cuando se usa una referencia de clase primaria para referirse a un objeto de clase secundaria como este:

Animal animal = new Animal(); Animal dog = new Dog();

Y sé que el polimorfismo se aplica a los métodos de clase, pero ¿también se aplica al atributo de clase? Traté de probar eso con este pequeño ejemplo:

public class Main{ public static void main(String args[]){ Animal animal = new Animal(); Animal dog1 = new Dog(); Dog dog2 = new Dog(); System.out.println("Animal object name: " + animal.name); System.out.println("Dog1 object name: "+dog1.name); System.out.println("Dog2 object name: " + dog2.name); animal.print(); dog1.print(); dog2.print(); } } class Animal{ String name = "Animal"; public void print(){ System.out.println("I am an: "+name); } } class Dog extends Animal{ String name = "Dog"; public void print(){ System.out.println("I am a: "+name); } }

Y esta es la salida:

Animal object name: Animal Dog1 object name: Animal Dog2 object name: Dog I am an: Animal I am a: Dog I am a: Dog

Como puede ver (espero que esté claro), el polimorfismo funciona bien con el método print () , pero con el atributo de clase "nombre", depende de la variable de referencia.

Entonces, ¿tengo razón? El polimorfismo no se aplica a los atributos de clase?


Básicamente, cuando una clase padre tiene un hijo, la clase hija debería parecerse totalmente a su padre, de lo contrario "¿Cómo se les puede llamar padre e hijo?" ¿derecho? De todos modos, se permite que la clase secundaria tenga un comportamiento diferente al de su padre. Eso tiene mucho sentido y es natural.

Pero si desea anular el atributo de una clase secundaria, puede hacerlo a través del mecanismo constructor

Ejemplo de código

class Animal{ String name; public Animal(){ name = "Animal"; } public Animal(String name){ this.name = name; } public void print(){ System.out.println("I am an: "+name); } } class Dog extends Animal{ Dog(){ super("Dog"); } public void print(){ System.out.println("I am a: "+name); } }

Verá que el nombre de atributo "Dog" en la clase Dog se pasa a través del constructor, que aquí podemos llamar constructor de la clase padre a través de una palabra clave super .

Resultados:

Animal object name: Animal Dog1 object name: Dog Dog2 object name: Dog I am an: Animal I am a: Dog I am a: Dog


Cuando extiende una clase, los métodos se anulan, pero los campos están ocultos. El despacho dinámico funciona para métodos, pero no para campos. ¿Por qué el lenguaje está diseñado así? Dios sabe por qué.


Cuando invocas el método de print en animal , JVM busca primero un método de print en un objeto dog . Si no hubiera print método de print en el objeto dog , JVM buscaría la superclase de Dog . Como encuentra el método de print en la clase Dog , comienza a ejecutarlo. El campo de nombre en la clase Dog oculta el campo de nombre que se heredó de la clase Animal . Es como:

public class Test { static String name = "xyz"; public static void main(String[] args) { { String name = "abc"; System.out.println(name); // abc is printed } System.out.println(name); // xyz is printed } }

Dentro del bloque, hay un name variable local. Entonces el name variable global está oculto. Pero cuando sales del bloque, la variable local entra en vigencia.

NOTA:

Dog clase de Dog debería ser como:

class Dog extends Animal{ this.name = "Dog"; public void print(){ System.out.println("I am a: " + this.name); } }

Lo que hiciste es un mal diseño.


El campo de Animal está oculto por el campo de Perro, aún puede acceder al campo de Animal haciendo referencia a él como lo hizo.

El comportamiento que espera puede lograrse de esta manera:

public class Main{ public static void main(String args[]){ Animal animal = new Animal(); Animal dog1 = new Dog(); Dog dog2 = new Dog(); System.out.println("Animal object name: " + animal.name); System.out.println("Dog1 object name: "+dog1.name); System.out.println("Dog2 object name: " + dog2.name); animal.print(); dog1.print(); dog2.print(); } } class Animal { String name = "Animal"; public void print(){ System.out.println("I am an: "+name); } } class Dog extends Animal{ public Dog() { this.name = "Dog" } }


En Java utilizamos el método set y get para acceder a un campo. En su ejemplo, tenemos una clase Perro que extiende una clase Animal.

Pero si lo declaras como un Animal, si llamas directamente al campo Amimal dog1 = new Dog(); crea una instancia de Dog, pero se declara como Animal, por lo que cuando llama a dog1.name , le da el valor de Animal.


Las variables no son polimórficas en Java; No se anulan unos a otros.

Editar: para respaldar aún más la respuesta de Solver , recuerdo que mi maestro de OOP afirma que cuando creas un objeto de Child class con una reference de la Parent class , las variables en Child class que no existen en la Parent class todavía tienen memoria asignada en el tiempo de ejecución pero no pueden se accede ya que no hay métodos en la Parent class que puedan acceder a una variable de la Child class .


No lo hace Las variables de instancia son propiedades de una clase específica y no se ven afectadas directamente por las superclases o subclases y el polimorfismo.

Aún puede acceder a ambos campos usando "super.name" y "this.name" en Dog, pero si usa solo "name", el de Dog se hará cargo. Si quieres el otro, explícitamente debes llamar a super. Tenga en cuenta que estoy hablando de acceder a las variables en la clase Dog .


Dog.name está ocultando Animal.name , y es un patrón muy malo hacerlo. Cualquier buen IDE te advertirá que lo estás haciendo.

Ambos campos de instancia existen, y puede acceder a ambos desde Dog como this.name y super.name .