public class SuperClass
{
public void method1()
{
System.out.println("superclass method1");
this.method2();
}
public void method2()
{
System.out.println("superclass method2");
}
}
public class SubClass extends SuperClass
{
@Override
public void method1()
{
System.out.println("subclass method1");
super.method1();
}
@Override
public void method2()
{
System.out.println("subclass method2");
}
}
public class Demo
{
public static void main(String[] args)
{
SubClass mSubClass = new SubClass();
mSubClass.method1();
}
}
mi salida esperada:
subclase método1
superclase método1
superclase método2
salida real:
subclase método1
superclase método1
subclase método2
Sé que técnicamente he anulado un método público, pero pensé que debido a que estaba llamando al super, cualquier llamada dentro del super permanecería en el super, esto no está sucediendo. ¿Alguna idea de cómo puedo hacer que suceda?
java
inheritance
overriding
super
jsonfry
fuente
fuente
Respuestas:
La palabra clave
super
no "se pega". Cada llamada a método se maneja individualmente, por lo que incluso si lo hicisteSuperClass.method1()
llamandosuper
, eso no influye en ninguna otra llamada a método que puedas realizar en el futuro.Eso significa que no hay una forma directa para llamar
SuperClass.method2()
desdeSuperClass.method1()
sin ir aunqueSubClass.method2()
menos que usted está trabajando con una instancia real deSuperClass
.Ni siquiera puede lograr el efecto deseado usando Reflection (consulte la documentación de
java.lang.reflect.Method.invoke(Object, Object...)
).[EDITAR] Todavía parece haber cierta confusión. Déjame intentar una explicación diferente.
Cuando invocas
foo()
, en realidad invocasthis.foo()
. Java simplemente le permite omitir elthis
. En el ejemplo de la pregunta, el tipo dethis
esSubClass
.Entonces, cuando Java ejecuta el código en
SuperClass.method1()
, finalmente llega athis.method2();
El uso
super
no cambia la instancia a la que apuntathis
. Entonces la llamada va aSubClass.method2()
ya quethis
es de tipoSubClass
.Tal vez sea más fácil de entender cuando imagina que Java pasa
this
como un primer parámetro oculto:Si sigue la pila de llamadas, puede ver que
this
nunca cambia, siempre es la instancia creada enmain()
.fuente
super
. Cada vez que llama a un método, mirará el tipo de instancia y comenzará a buscar el método con este tipo, sin importar la frecuencia con la que lo llamesuper
. Por lo tanto, cuando llamemethod2
a una instancia deSubClass
, siempre verá laSubClass
primera.super
no cambia la instancia. No establece ningún campo oculto "a partir de ahora, todas las llamadas a métodos deberían comenzar a usarseSuperClass
". O para decirlo de otra manera: el valor dethis
no cambia.Solo puede acceder a los métodos reemplazados en los métodos de reemplazo (o en otros métodos de la clase de reemplazo).
Entonces: o no anule
method2()
o llamesuper.method2()
dentro de la versión anulada.fuente
Estás usando la
this
palabra clave que en realidad se refiere a la "instancia en ejecución del objeto que estás usando", es decir, estás invocandothis.method2();
en tu superclase, es decir, llamará al método2 () en el objeto que ' que está usando, que es la subclase.fuente
this
tampoco ayudará. Una invocación no calificada utiliza implícitamentethis
method2()
, verá el compiladorthis.method2()
. Entonces, incluso si quita elthis
, aún no funcionará. Lo que @Sean Patrick Floyd está diciendo es correctothis
this
refiere a la "clase de instancia de ejecución concreta" (conocida en tiempo de ejecución) y no (como parece creer el autor) a la "clase de unidad de compilación actual" (donde se usa la palabra clave, conocida en tiempo de compilación). Pero también puede ser engañoso (como señala Shervin):this
también se hace referencia implícitamente con la llamada al método simple;method2();
es lo mismo quethis.method2();
Lo pienso de esta manera
Déjame mover esa subclase un poco hacia la izquierda para revelar lo que hay debajo ... (Hombre, me encantan los gráficos ASCII)
En otras palabras, citando la especificación del lenguaje Java :
En términos
this
sencillos , es básicamente un objeto (* el ** objeto; el mismo objeto que se puede mover en variables), la instancia de la clase instanciada, una variable simple en el dominio de datos;super
es como un puntero a un bloque de código prestado que desea que se ejecute, más como una mera llamada a función, y es relativo a la clase donde se llama.Por lo tanto, si usa
super
de la superclase, obtiene código de la clase superduper [el abuelo] ejecutado), mientras que si usathis
(o si se usa implícitamente) de una superclase, sigue apuntando a la subclase (porque nadie lo ha cambiado, y nadie podría).fuente
Si no desea que superClass.method1 llame a subClass.method2, haga que el método2 sea privado para que no se pueda anular.
He aquí una sugerencia:
Si no funcionara de esta manera, el polimorfismo sería imposible (o al menos ni la mitad de útil).
fuente
Dado que la única forma de evitar que un método se anule es usar la palabra clave super , he pensado en subir el método2 () de SuperClass a otra nueva clase Base y luego llamarlo desde SuperClass :
Salida:
fuente
this
siempre se refiere al objeto que se está ejecutando actualmente.Para ilustrar más el punto, aquí hay un bosquejo simple:
Si tiene una instancia de la caja exterior, un
Subclass
objeto, dondequiera que se aventure dentro de la caja, incluso en elSuperclass
'área', sigue siendo la instancia de la caja exterior.Además, en este programa solo hay un objeto que se crea de las tres clases, por
this
lo que solo puede hacer referencia a una cosa y es:como se muestra en "Heap Walker" de Netbeans .
fuente
vocación
salidas
fuente
No creo que puedas hacerlo directamente. Una solución alternativa sería tener una implementación interna privada del método2 en la superclase y llamar a eso. Por ejemplo:
fuente
"esta" palabra clave se refiere a la referencia de clase actual. Eso significa que, cuando se usa dentro del método, la clase 'actual' sigue siendo SubClass y, por lo tanto, se explica la respuesta.
fuente
Para resumir, esto apunta al objeto actual y la invocación del método en Java es polimórfica por naturaleza. Entonces, la selección del método para la ejecución depende totalmente del objeto señalado por este. Por lo tanto, la invocación del método method2 () de la clase principal invoca el método2 () de la clase secundaria, ya que this apunta al objeto de la clase secundaria. La definición de esto no cambia, independientemente de la clase que se use.
PD. a diferencia de los métodos, las variables miembro de clase no son polimórficas.
fuente
Durante mi investigación para un caso similar, terminé verificando el seguimiento de la pila en el método de subclase para averiguar de dónde proviene la llamada. Probablemente haya formas más inteligentes de hacerlo, pero me funciona y es un enfoque dinámico.
Creo que la cuestión de tener una solución para el caso es razonable. Por supuesto, hay formas de resolver el problema con diferentes nombres de métodos o incluso con diferentes tipos de parámetros, como ya se mencionó en el hilo, pero en mi caso no me gustaría confundir con diferentes nombres de métodos.
fuente
Más extendido el resultado de la pregunta planteada, esto dará más información sobre el especificador de acceso y el comportamiento de anulación.
fuente