viernes, 11 de septiembre de 2020

Caso muy especifico de herencia y override en Java

Teniendo una estructura de herencia 


Donde

- Tenemos isBiped overriden en Kangaroo

- Kangaroo hereda el metodo getMarsupialDescription

Si implementamos la siguiente logica en el main de Kangaroo
 public class Marsupial {  
   public boolean isBiped() {  
     return false;  
   }  
   public void getMarsupialDescription() {  
     System.out.println("Marsupial walks on two legs: " + isBiped());  
   }  
 }  
 class Kangaroo extends Marsupial {  
   public boolean isBiped() {  
     return true;  
   }  
   public void getKangarooDescription() {  
     System.out.println("Kangaroo hops on two legs: " + isBiped());  
   }  
   public static void main(String[] args) {  
        Marsupial marsupialOne = new Marsupial();
        marsupialOne.getMarsupialDescription(); 
        marsupialOne.getKangarooDescription(); 

        // Marsupial Ref, Kangaroo obj        
        Marsupial marsupialTwo = new Kangaroo();
        marsupialTwo.getMarsupialDescription();
        marsupialTwo.getKangarooDescription(); 

        // Kangaroo Ref & obj
        Kangaroo kangaroo = new Kangaroo();
        kangaroo.getMarsupialDescription(); 
        kangaroo.getKangarooDescription(); 
   }  
 }  





Tenemos un output:
 
$ javac Marsupial.java
Marsupial.java:27: error: cannot find symbol
        marsupialOne.getKangarooDescription(); 
                    ^
  symbol:   method getKangarooDescription()
  location: variable marsupialOne of type Marsupial
Marsupial.java:32: error: cannot find symbol
        marsupialTwo.getKangarooDescription(); 
                    ^
  symbol:   method getKangarooDescription()
  location: variable marsupialTwo of type Marsupial
2 errors
Tratando de explicar este resultado debo primero lanzar una hipotesis de lo que esta haciendo la JVM

Al compilar

 
Marsupial marsupialOne = new Marsupial();
marsupialOne.getMarsupialDescription(); 
marsupialOne.getKangarooDescription();
Al ser marsupial una referencia tipo Marsupial, el compilador busca en esta clase la definicion de los metodos getMarsupialDescription y getKangarooDescription, y solamente encuentra el primero, el segundo no esta definido en esta clase por lo cual arroja el primer error

Para el caso:


 
Marsupial marsupialTwo = new Kangaroo();
marsupialTwo.getMarsupialDescription();
marsupialTwo.getKangarooDescription();
En este caso aunque el objeto es de tipo Kangaroo, la referencia en la que se almacena es de tipo Marsupial, el compilador, entonces, busca en esta clase la definicion de los metodos getMarsupialDescription y getKangarooDescription, y solamente encuentra el primero, el segundo no esta definido en esta clase por lo cual arroja el segundo error

En tiempo de compilacion aun no existe ningun objeto, asi que la JVM se limita a examinar la definicion de las clases


 
Kangaroo kangaroo = new Kangaroo();
kangaroo.getMarsupialDescription();
kangaroo.getKangarooDescription();
kangaroo es un objeto de tipo Kangaroo, la referencia en la que se almacena es de tipo Kangaroo, el compilador, entonces, busca en esta clase la definicion de los metodos getMarsupialDescription y getKangarooDescription, y solamente encuentra el segudno, el primero no esta definido en esta clase, entonces, busca en la clase padre, donde si encuentra la definicion y da por valida la sentencia

Se puede corregir los errores removiendo las lineas


 
marsupialOne.getKangarooDescription();
...
marsupialTwo.getKangarooDescription();
Output:
 
Marsupial walks on two legs: false
Marsupial walks on two legs: true
Marsupial walks on two legs: true
Kangaroo hops on two legs: true
Sabiendo que getMarsupialDescription llama al metodo isBiped, ¿porque hay resultados diferentes en marsupialOne y marsupialTwo? La respuesta es que marsupialOne es un objeto de tipo Marsupial y y marsupialTwo es un objeto Kagaroo, y estas clases tienen su propia implementacion del metodo isBiped, a la cual llaman respectivamente
Que ocurre si cambiamos la implementacion de isBiped a static en las dos classes
 
public static boolean isBiped()
 
Marsupial walks on two legs: false
Marsupial walks on two legs: false
Marsupial walks on two legs: false
Kangaroo hops on two legs: true 
En este caso, al ser isBiped un metodo estatico esta vinculado al tipo de referencia, no al objeto, asi, cuando se llama getMarsupialDescription usando una referencia Marsupial, se llama al metodo estatico isBiped de esa clase en particular