multiple - Salida perpleja en Java con métodos de herencia y anulación
herencia multiple en java ejemplos (1)
Hay algunos hechos que debe saber antes de comenzar a explicar cada paso de la ejecución del código:
- Las referencias de campo se resuelven según el tipo de referencia y las llamadas al método se resuelven durante el tiempo de ejecución (de forma dinámica) en función del tipo de objeto.
-
super()se coloca implícitamente en cada constructor, incluso si no lo pones allí mismo (no se llama si llamas asuper(int x, int y)por ejemplo). - Se considera una muy mala práctica llamar a los métodos "anulables" de un constructor; verás por qué cuando pasamos por la ejecución.
Ahora desglosemos su código paso a paso:
- Crea una instancia de
Bllamando a su constructor predeterminadoB(). - Como dije antes, la llamada a
super()se agrega implícitamente a cualquier constructor, por lo queA()se llama inmediatamente. - Dentro de
A()llama afoo(), que está anulado en la claseBy es por eso que se llama afoo()desdeB - Dentro de
foo()Bobtienes la salidaB.foo(): bar = nullya que Java no llegó a inicializar los campos deB(¡su constructor no se ha ejecutado todavía!) Y los campos de tipo de objeto se inicializan anullpor defecto. - Ahora que hemos terminado con el constructor de
A()volvemos al constructor deB(). - Dentro de dicho constructor, tenemos la llamada a
foo()otra vez, que es otra vezB''sfoo(). Pero a diferencia de la última vez,Btiene sus campos inicializados (después de la llamada asuper()) correctamente, por lo que obtienes el esperadoB.foo(): bar = B.bar. - Ahora hemos vuelto al cálido abrazo de
main. - Usted accede a
a.bar, y como dije que las referencias de campo se resuelven según el tipo de referencia, obtiene labarde campo deA - Por último, por la misma razón, se llama
a.foo()que de nuevo desencadena elfoo()Bque imprimeb.baruna vez más.
Y hemos terminado! :)
Referencias adicionales y materiales de lectura que valen la pena:
Explicación estática y dinámica explicada
Orden de llamadas de constructor
Me encontré con esta pieza de código.
Traté de adivinar cuál será el resultado de ejecutarlo antes de hacerlo realmente. Estaba realmente confundido cuando los vi y necesitaba algunas explicaciones.
Este es el código:
public class A {
String bar = "A.bar";
A() { foo(); }
public void foo() {
System.out.println("A.foo(): bar = " + bar);
}
}
public class B extends A {
String bar = "B.bar";
B() { foo(); }
public void foo() {
System.out.println("B.foo(): bar = " + bar);
}
}
public class C {
public static void main(String[] args) {
A a = new B();
System.out.println("a.bar = " + a.bar);
a.foo();
}
}
El resultado es:
B.foo(): bar = null
B.foo(): bar = B.bar
a.bar = A.bar
B.foo(): bar = B.bar
¿Porqué es eso?
- ¿Cómo es
bar = null? - ¿Por qué aparece
a.bar = A.barincluso? No he instanciadoAen absoluto. - Y si aparece
A, ¿por qué es después deB?