2011-01-29 9 views
29
public class A { 
    public void f1(String str) { 
     System.out.println("A.f1(String)"); 
     this.f1(1, str); 
    } 

    public void f1(int i, String str) { 
     System.out.println("A.f1(int, String)"); 
    } 
} 



public class B extends A { 
    @Override 
    public void f1(String str) { 
     System.out.println("B.f1(String)"); 
     super.f1(str); 
    } 

    @Override 
    public void f1(int i, String str) { 
     System.out.println("B.f1(int, String)"); 
     super.f1(i, str); 
    } 
} 


public class Main { 
    public static void main(String[] args) { 
     B b = new B(); 
     b.f1("Hello"); 
    } 
} 

Estoy en busca de que este código de salida:clase base de la función anulada método de clase base

B.f1(String) 
A.f1(String) 
A.f1(int, String) 

Sin embargo, yo estoy consiguiendo:

B.f1(String) 
A.f1(String) 
B.f1(int, String) 
A.f1(int, String) 

entiendo que bajo la contexto de B "esto" en A.f1 (Cadena) es la instancia de B. ¿Tengo la opción de hacer la cadena nueva B1(). F1 (Cadena) -> (A) f1 (Cadena) -> (A) f1 (int, Cadena)?

Esta es una pregunta teórica, prácticamente la solución sería, obviamente, en A implementar una función privada que llamarían f1 (String) y f1 (int, String).

Gracias,
Maxim.

+2

Intenté usar la reflexión (obtener un objeto de método para A's f1 (int, String) e invocarlo), pero no funcionó. Esta [entrada de blog] [1] en los blogs de Sun señala que esto no es posible con Java. [1]: http://blogs.sun.com/sundararajan/entry/calling_overriden_superclass_method_on – esaj

+0

@esaj agradable encontrar en el enlace –

Respuesta

29

Desafortunadamente, ninguna

Como estoy seguro de que está consciente, pero lo declarar explícitamente que está completo: solo hay 2 palabras clave para controlar la invocación al método:

  • este - - ve para el método a partir de la clase de la instancia invocando (tabla virtual "top" de la instancia - por defecto implícita)
  • súper-super.method() - ve para el método a partir de la clase padre de la clase en la que el invocando el método está definido (la clase de invocación mesa virtual de padres - not strictly true, pero más simple de pensar de esta manera - gracias @maaartinus)

me puedo imaginar otra palabra clave (por ejemplo, ? Actual) hace lo que usted describe:

  • actual - current.method() - ve para el método a partir de la clase en la que está definido el método de invocación

pero Java no tienen una palabra clave (¿todavía?).

+0

AFAIK, 'super.method()' no comienza en la VT del padre. No hay ninguna búsqueda de VT en absoluto, funciona de una manera similar a llamar a métodos privados. AFAIK, se compila utilizando invokespecial. – maaartinus

+0

@maaartinus - gracias - ah, me encanta aprender algo nuevo todos los días. Por lo tanto, no existe la instrucción 'invokevirtualstartingfromparent';' invokespecial' se usa para la llamada 'super' y' invokespecial' utiliza el enlace en tiempo de compilación. Entonces, en el momento de la llamada 'super', sabemos lo suficiente sobre el tipo de resolución de compilación en tiempo del método objetivo. Si ese método ** no ** se implementa en la superclase directa, entonces supongo que aún es necesario el equivalente de una búsqueda en la jerarquía. ¿El resultado final es efectivamente el mismo? –

+0

No creo que haya ninguna búsqueda en el tiempo de ejecución, ni siquiera en este caso. IIUIC, 'super' significa en realidad * primer ancestro que lo tiene *. El compilador debe conocer toda la jerarquía, por lo que escribe el ancestro correcto en el archivo de clase. En caso de que el método no esté allí (lo cual se puede hacer solo con trucos usando otro archivo de clase), se lanza un NoSuchMethodError. – maaartinus

5

Los métodos reemplazados en Java están vinculados dinámicamente. es decir, el tipo de instancia real del objeto dicta cómo se llamará. final métodos (que no pueden ser reemplazados) y private métodos (que no pueden ser heredados) están vinculados estáticamente.

En C++, por el contrario, tendría que hacer explícitamente las funciones virtual para obtener el mismo comportamiento.

16

me temo, es imposible, pero hay una solución simple:

public class A { 
    public void f1(String str) { 
     System.out.println("A.f1(String)"); 
     privateF1(1, str); 
    } 

    private void privateF1(int i, String str) { 
     System.out.println("A.f1(int, String)"); 
    } 

    public void f1(int i, String str) { 
     privateF1(i, str); 
    } 
} 
+2

prefijar una llamada al método con 'this.' siempre es redundante. –

-2
package main; 

public class A { 
public void f1(String str) { 
    System.out.println("A.f1(String)"); 
    if (this instanceof B) 
     new A().f1(1, str); 
    else 
     this.f1(1, str); 
} 

public void f1(int i, String str) { 
    System.out.println("A.f1(int, String)"); 
} 

} 

class B extends A { 
@Override 
public void f1(String str) { 
    System.out.println("B.f1(String)"); 
    super.f1(str); 
} 

@Override 
public void f1(int i, String str) { 
    System.out.println("B.f1(int, String)"); 
    super.f1(i, str); 
} 

public static void main(String[] args) { 
A a = new B(); 
    a.f1("Hello"); 
} 
} 
+0

** Esta pregunta tenía más de 3 años. ** Simplemente publique un código sin ninguna explicación. También un defecto en tu diseño es que la clase 'A' necesita saber todas sus subclases (' B' en este caso simple), lo cual es difícil si quieres crear una nueva subclase porque entonces tienes que ajustar la clase 'A' además. –

Cuestiones relacionadas