Hace unos días publicaba un tweet con un problema de Java aparentemente sencillo pero que tiene más complejidad que la que parece a primera vista. Como escribir la explicación en Twitter es un poco complicado y ante algunas preguntas que me habéis hecho a continuación va la solución del puzle y su explicación.
El problema
En primer lugar pongo de nuevo el problema en un formato en el cual es más fácil copiarlo, por si alguien lo quiere probar en su computadora
class A { public void m(A a) { System.out.println("1"); } } class B extends A { public void m(B b) { System.out.println("2"); } public void m(A a) { System.out.println("3"); } } class Puzzle { public static void main(String[] args) { B b = new B(); A a = b; a.m(b); } }
La solución
Cualquiera puede comprobar que la solución dada es «3«. Algo que no resulta muy obvio a primera vista. Si alguien tiene dudas puede a probar a ejectuarlo on-line en el siguiente enlace: https://ideone.com/rUOtfB
La explicación
Para explicar el resultado hay que tener en cuenta los distintos aspectos de la orientación a objetos que están teniendo lugar.
Sobrecarga. En primer lugar sobrecarga, el método «m» está sobrecargado en la clase «B» (tiene dos métodos con el mismo nombre pero distinto tipo de parámetros). Si sólo entrara a jugar la sobrecarga Java se decidiría por el método «2» al ser el más específico. Por ejemplo, el siguiente código da como resultado «2».
class A { // ... } class B extends A { public void m(B b) { System.out.println("2"); } public void m(A a) { System.out.println("3"); } } class Puzzle { public static void main(String[] args) { B b = new B(); b.m(b); } }
Sobrescritura. No solo está ocurriendo sobrecarga sino también sobrescritura, el método «3» es una sobrescritura del método «1» situado en la clase padre. Cuado llamemos a ese método desde una instancia de la subclase se ejecutará la versión de la superclase.
Polimorfismo de inclusión (o de herencia). Una subclase puede pasarse en el lugar donde nos piden una superclase. En este caso a una variable definida de tipo A se le pasa una instancia de la clase B.
Restricción de llamada a la característica del tipado estricto. Básicamente dice que para llamar a un método desde una variable declarada de tipo A, entonces ese método tiene que estar en la clase A (o en alguna superclase).
Así que lo que ocurre es que al hacer la llamada a «a.m(b)», como la variable «a» está definida como de la clase «A» se busca al método «m» en la clase «A». Sin embargo como en la variable «a» hay una instancia de «b» (subclase de «A») se busca la versión sobrescrita de ese método en la clase «B». Pero es la versión del método que hay en «A», es decir, la que tiene un parámetro de tipo «A» como es el método que imprime «3».
Si en la clase «A» el método se define como «public void m(Object a)» entonces no hay sobrescritura e imprimiría «1», si el método fuera «public void m(B a)» habría sobrescritura con el otro método de «B» e imprimiría «2»
Primeramente saludarlo , solo queria comentarle que mi persona seguia los video tutoriales sobre java que habia en youtube que usted creaba , el cual eran excelentes ahora ya no estan disponibles, hacerle una peticion no habría alguna manera de compartirlo nuevamente o que su persona la publique por favor ya que eran de gran ayuda para aquellos que nos interesa aprender este lenguaje, bueno me despido y le mando un saludo grato desde Bolivia, adios.