O polymorphism se aplica aos atributos de class em Java?

Eu sei que o uso comum de polymorphism na OOP ocorre quando uma referência de class pai é usada para se referir a um object de class filho como este:

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

E eu sei que o polymorphism se aplica aos methods de class, mas também se aplica ao atributo de class? Eu tentei testar isso com este pequeno exemplo:

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

E esta é a saída:

 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 você pode ver (espero que esteja claro), o polymorphism funciona bem com o método print () , mas com o atributo class “name”, depende da variável de referência.

Então estou certo? o polymorphism não se aplica aos atributos de class?

Quando você estende uma class, os methods são sobrescritos, mas os campos são ocultos. O despacho dynamic funciona para methods, mas não para campos. Por que a linguagem é projetada assim, Deus sabe por quê.

Não, não. As variables ​​de instância são propriedades de uma class específica e não são afetadas diretamente por super ou subclasss e polymorphism.

Você ainda pode acessar os dois campos usando “super.name” e “this.name” no Dog, mas se você usar apenas “name”, o nome do Dog assumirá. Se você quer o outro, você precisa explicitamente ligar para o super. Note que estou falando sobre o access às variables na class Dog .

Dog.name está escondendo Animal.name , e é um padrão muito ruim para fazer isso. Qualquer bom IDE irá avisá-lo que você está fazendo isso.

Ambos os campos de instância existem e você pode acessar ambos do Dog como this.name e super.name .

O campo Animal está oculto pelo campo Dog, você ainda pode acessar o campo Animal, referenciando-o como você fez.

O comportamento que você espera pode ser alcançado desta maneira:

 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" } } 

Variáveis ​​não são polimórficas em Java; eles não se sobrepõem.

Edit: Para suportar ainda mais a resposta do Solver , lembro-me do meu professor de OOP, alegando que quando você cria um object da Child class com uma reference da Parent class , as variables na Child class que não existem na Parent class ainda são alocadas na memory mas não podem ser acessado, pois não há methods na Parent class que poderiam acessar uma variável da Child class .

Basicamente, quando uma class pai tem um filho, a class filha deve se parecer totalmente com seu pai, do contrário “Como você pode chamá-lo de pai e filho?” certo? De qualquer forma, a class filha pode ter um comportamento diferente do pai. Isso faz sentido e natural.

Mas se você quer sobrescrever o atributo de uma class filha, você pode fazê-lo através do mecanismo do construtor.

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

Você verá que o nome do atributo "Dog" na class Dog é passado através do construtor que aqui podemos chamar de construtor da class pai através de uma palavra-chave 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 

Quando você invoca o método de print no animal , a JVM procura primeiro um método de print no object dog . Se não houvesse um método de print no object dog , a JVM procuraria a superclass de Dog . Desde que encontra o método de print na class Dog , ele começa a executá-lo. O campo de nome na class Dog oculta o campo de nome que foi herdado da class Animal . É 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 do bloco, há um name variável local. Portanto, o name variável global está oculto. Mas quando você sai do bloco, a variável local entra em vigor.

NOTA:

Dog class do Dog deve ser como:

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

O que você fez é um design ruim.

Em Java, usamos set e get method para acessar um campo. No seu exemplo, temos uma class Dog estendendo uma class Animal.

Mas se você declarar isso como Animal, se você chamar diretamente o campo Amimal dog1 = new Dog(); você cria uma instância Dog, mas é declarada como Animal, então quando você chama dog1.name , ela lhe dá o valor de Animal.