sirve - settitle java
Súper palabra clave en Java, comportamiento interesante, por favor explique (3)
Digamos que tenemos el siguiente código:
class A {
public void doLogic() {
System.out.println("doLogic from A");
}
}
class B extends A {
@Override
public void doLogic() {
System.out.println("doLogic from B");
}
public void doDifferentLogic() {
System.out.println("doDifferentLogic from B");
super.doLogic();
}
}
class C extends B {
@Override
public void doLogic() {
System.out.println("doLogic from C");
}
}
public class Test {
public static void main(String[] args) {
C c = new C();
c.doDifferentLogic();
}
}
Cuando ejecutamos este código, el comportamiento esperado es el siguiente: como c contiene una referencia al objeto de clase C, cuando se invoca el método c.doDifferentLogic()
, la JVM busca el método en la clase C y, como no se encuentra, comienza a mirar el árbol de herencia. Como se esperaba, el método doDifferentLogic()
se encuentra en la doDifferentLogic()
y se ejecuta. Sin embargo, se espera que el constructo super.doLogic()
se vea desde la referencia actual "Point of View", que es de tipo C. Entonces, el super de C debería B, pero en su lugar se invoca el método de la clase A superior.
Si elimina la palabra clave super
o la reemplaza con la palabra clave this
(que es lo mismo que "this" está implícita), obtiene el comportamiento polimórfico esperado y se doLogic()
de la clase C.
Entonces mi pregunta es: ¿Debería llamar a super.doLogic()
ser this.super.doLogic()
(2), en lugar de static.super.doLogic()
(1)?
Ambas son construcciones inválidas, están aquí solo para tratar de explicarme mejor.
(1) o en otras palabras: de la referencia al objeto actual c, obtenga la superclase del objeto actual e invoque el método doLogic()
lugar de (2) de esta clase obtenga la superclase e invoque su método doLogic()
Aquí es donde el JLS define esto específicamente :
- Si la forma es super. NonWildTypeArguments opt identificador , luego el nombre del método es el identificador y la clase a buscar es la superclase de la clase cuya declaración contiene la invocación del método.
Por lo tanto, Java considera super
como una referencia a la superclase de la clase que incluye la llamada a super.method
, no al tipo de tiempo de ejecución real.
En Java, la palabra clave super
siempre se refiere a la superclase del tipo en el que se utiliza la palabra clave, no a la superclase del tipo dinámico del objeto en el que se invoca el método. En otras palabras, super
se resuelve estáticamente, no dinámicamente. Esto significa que en el contexto de la clase B
, la palabra clave super
siempre se refiere a la clase A
, independientemente de si el método B
se ejecuta utilizando un objeto C
como el receptor. A mi leal saber y entender, no hay una manera de determinar dinámicamente el tipo de superclase y utilizar sus métodos sin usar el reflejo.
¡Espero que esto ayude!
Siempre que se ejecute el super.doLogic () de classB, siempre se referirá al método doLogic () de la superclase de classB que en este caso sería classA. Este es el comportamiento deseado para que el control no siga pasando entre las clases dentro del mismo método. Este es el concepto de un contexto de clase. Una vez que esté en el contexto de una clase, tendrá que seguir las reglas establecidas por esa clase y no seguir pasando el control entre diferentes contextos.