2010-08-11 32 views
31

Digamos que tengo tres clases A, B y C.Llamando al método de clase super super

  • B se extiende Un
  • C parte B

Todos tienen un método public void foo() definido.

Ahora del método de C foo() Quiero invocar el método de A foo() (NO es el método de su padre B sino el método de la súper super clase A).

Intenté super.super.foo();, pero su sintaxis no es válida. ¿Cómo puedo lograr esto?

+1

Simplemente porque alguien debería preguntar, ¿por qué C extiende B si parece querer que se extienda A directamente? (Imagino que hay otras partes en las que confía en la funcionalidad de B, o algo así) –

+0

El foo() de A se puede invocar desde C usando super.foo() solo si B no anula el foo() de A. – YoK

+1

_ Effective Java 2nd Edition, Item 16: Favor de la composición sobre la herencia_. Además, mira el patrón del decorador; puede adaptarse a su necesidad mejor. – polygenelubricants

Respuesta

30

Ni siquiera puedes usar el reflejo. Algo así como

Class superSuperClass = this.getClass().getSuperclass().getSuperclass(); 
superSuperClass.getMethod("foo").invoke(this); 

conduciría a un InvocationTargetException, porque incluso si se llama al método foo-en el superSuperClass, se siguen utilizando C.foo() cuando se especifica "este" en Invocar. Esto es una consecuencia del hecho de que todos los métodos de Java son métodos virtuales.

Parece que necesita ayuda de la clase B (por ejemplo, al definir un método superFoo(){ super.foo(); }).

Dicho esto, parece que se trata de un problema de diseño si intenta algo como esto, por lo que sería útil darnos algunos antecedentes: ¿Por qué necesita hacer esto?

+1

No era mi requisito. Estaba pensando en mi cabeza todas las posibilidades de jugar con la herencia y recibí esta pregunta. Gracias ... Obtuve la respuesta – Harish

+0

Bueno, necesito hacerlo porque la superclase anula la súper clase de una manera que no quiero ... y es una biblioteca ... así que quiero llamar al de super súper clase ... tal vez tomar el código fuente del método de la súper-clase y anular de nuevo resuelve esto? – xdevs23

+0

Por supuesto, puede escribir en su método lo que desee, por lo que en este caso, copiar el código debería funcionar. Sin embargo, si la súper-clase superior utiliza campos o métodos privados o paquetes privados en 'foo()', necesita reflexión para acceder a ellos (y, por supuesto, no tiene suerte si tiene un administrador de seguridad). Además, si el código 'foo()' original hace llamadas 'super', tampoco funcionaría. – Landei

0

No es posible, solo podemos llamar a las implementaciones de superclase.

+0

(Aarons estaba demasiado impresionado por la respuesta eliminada que Eliminé el mío dos segundos después de la publicación;) - lo recuperé aunque ahora hay mejores respuestas disponibles) –

19

No se puede - porque rompería la encapsulación.

Usted es capaz de llamar al método de su superclase, porque se asume que usted sabe lo que rompe la encapsulación en su propia clase , y evitar que ... pero usted no sabe qué reglas de su superclase está haciendo cumplir - por lo que no se puede omitir una implementación allí.

+0

Impar ... Recuerdo que había una forma de llamar a Object.toString() incluso si toString() fue sobrecargado por una superclase. Pero 'Type.this' no compila. : -/ –

+1

@ Aaron: no estoy seguro sobre Object.toString() - ¿estabas pensando en 'System.identityHashCode'? –

+0

Nunca lo usé, estoy bastante seguro de que era toString(). Object.super.toString() tampoco funciona. Tal vez fue un error en una versión temprana de Java o algo así. –

3

No puede hacerlo de una manera sencilla.

Esto es lo que creo que puede hacer:

Tener un bool en su clase B. Ahora debe llamar foo de B de C como [super foo] pero antes de hacer esto establecer el bool true. Ahora en el foo de B comprueba si el bool es verdadero, entonces no ejecutes ningún paso en eso y solo llames a A foo.

Espero que esto ayude.

+6

Ese es el hack Java más salvaje jamás :) –

+2

La respuesta de Jon Skeet es la mejor: este tipo de funcionalidad no debe habilitarse porque rompe la encapsulación. En lugar de dirigirse a _HOW_ para hacer algo como esto, deberíamos abordar el _WHY_ ¿alguien querría hacer algo como esto (y romper ese argumento por violar los principios de OOP). – polygenelubricants

+2

@Nikita Rybak: La gente pregunta por cosas que no deberían ser preguntadas. De ahí las respuestas que no deberían darse;) –

0

I smell algo a pescado aquí.

¿Estás seguro de que no estás exagerando demasiado "solo porque deberías poder hacerlo"? ¿Estás seguro de que este es el mejor patrón de diseño que puedes obtener? ¿Has intentado refactorizarlo?

0

Tuve un problema donde una superclase llamaría a un método de clase superior que se anuló. Esta fue mi solución ...

// ESTA LLAMANDO fallaría superclase MÉTODOS como A1() podría invocar el método de primera clase

class foo1{ 
public void a1(){ 
    a2(); 
    } 
public void a2(){} 
} 
class foo2 extends foo1{ 
{ 
public void a1(){ 
//some other stuff 
super.a1(); 
} 
public void a2(){ 
//some other stuff 
super.a2(); 
} 

// Se realiza el derecho superclase métodos se llaman // los métodos públicos sólo llamar a métodos privados por lo que todo los métodos públicos pueden anularse sin afectar la funcionalidad de la superclase.

class foo1{ 
public void a1(){ 
    a3();} 
public void a2(){ 
    a3();} 
private void a3(){ 
//super class routine 
} 
class foo2 extends foo1{ 
{ 
public void a1(){ 
//some other stuff 
super.a1(); 
} 
public void a2(){ 
//some other stuff 
super.a2(); 
} 

Espero que esto ayude. :)

+0

esto realmente no responde la pregunta. por favor vuelve a leer la pregunta. – Aboutblank

0

Antes de usar la API de reflexión, piense en el costo de la misma.

Es simplemente fácil de hacer. Por ejemplo:

C subclase de B y B subclase de A. Ambas tienen el método methodName() por ejemplo.

public abstract class A { 

    public void methodName() { 
    System.out.println("Class A"); 
    } 

} 


public class B extends A { 

    public void methodName() { 
     super.methodName(); 
     System.out.println("Class B"); 
    } 

    // Will call the super methodName 
    public void hackSuper() { 
     super.methodName(); 
    } 

} 

public class C extends B { 

    public static void main(String[] args) { 
     A a = new C(); 
     a.methodName(); 
    } 

    @Override 
    public void methodName() { 
     /*super.methodName();*/ 
     hackSuper(); 
     System.out.println("Class C"); 
    } 

} 

clase de ejecución C de salida será: Clase A Clase C

lugar de salida: Clase A Clase B Clase C

2

Para citar una respuesta anterior "Usted puede' t - porque rompería la encapsulación ". a lo que me gustaría añadir que:

Sin embargo, hay un caso de esquina donde se puede, es decir, si el método es static (public o protected). No puedes overwrite the static method.

Tener un método public static es trivial para demostrar que puede hacerlo.

Para protected, sin embargo, necesita uno de sus métodos para realizar una conversión a cualquier superclase en la ruta de herencia y se llamará a ese método de superclase.

Este es el caso esquina estoy explorando en mi respuesta:

public class A { 
    static protected callMe(){ 
     System.out.println("A"); 
    } 
} 

public class B extends A { 
    static protected callMe(){ 
     System.out.println("B"); 
    } 
} 

public class C extends B { 
    static protected callMe(){ 
     System.out.println("C"); 
     C.callMe(); 
    } 

    public void accessMyParents(){ 
     A a = (A) this; 
     a.callMe(); //calling beyond super class 
    } 
} 

La respuesta sigue siendo todavía No, pero sólo quería mostrar un caso donde se puede, aunque probablemente no tendría ningún sentido y es solo un ejercicio.

2

Sí, puedes hacerlo. Esto es un truco. Intenta no diseñar tu programa así.

+0

¡Esto se llama inversión de control! –