2010-08-11 5 views
31

Disons que j'ai trois classes A, B et C.appel super super méthode de classe

  • B extends A
  • C étend B

Tous ont une méthode public void foo() définie.

Maintenant, à partir de la méthode foo() de C, je veux appeler la méthode foo() de A (PAS la méthode de son parent B mais la méthode super super classe A).

J'ai essayé super.super.foo();, mais sa syntaxe n'est pas valide. Comment puis-je y parvenir?

+1

Juste parce que quelqu'un devrait demander, pourquoi C étend B si vous semblez vouloir étendre A directement? (J'imagine qu'il y a d'autres parties pour lesquelles vous comptez sur la fonctionnalité de B) –

+0

A foo() peut être appelé depuis C en utilisant super.foo() seulement si B ne remplace pas foo() de A. – YoK

+1

_Effective Java 2e édition, article 16: Favoriser la composition sur l'héritage_. En outre, consultez le motif décorateur; cela peut mieux convenir à votre besoin. – polygenelubricants

Répondre

30

Vous ne pouvez même pas utiliser la réflexion. Quelque chose comme

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

conduirait à une InvocationTargetException, parce que même si vous appelez la foo-Méthode sur la superSuperClass, il utilisera toujours C.foo() lorsque vous spécifiez « ce » dans Invoke. Ceci est une conséquence du fait que toutes les méthodes Java sont des méthodes virtuelles.

Il semble que vous ayez besoin d'aide de la classe B (par exemple en définissant une méthode superFoo(){ super.foo(); }). Cela dit, cela ressemble à un problème de conception si vous essayez quelque chose comme ça, donc il serait utile de nous donner quelques informations de base: Pourquoi vous avez besoin de faire cela?

+1

Ce n'était pas mon exigence. Je pensais juste à sortir de ma tête toutes les possibilités de jouer avec l'héritage et j'ai eu cette question. Merci .. J'ai la réponse – Harish

+0

Eh bien, j'ai besoin de faire cela parce que la super classe remplace la classe super super d'une manière que je ne veux pas .. et c'est une bibliothèque ... donc je veux appeler celui de super super classe ... peut-être prendre le code source de la méthode de la super super classe et déroger à nouveau résout cela? – xdevs23

+0

Bien sûr, vous pouvez écrire dans votre méthode ce que vous voulez, donc dans ce cas, la copie du code devrait fonctionner. Cependant, si la super-super-classe utilise des champs ou des méthodes privés ou de paquet privé dans 'foo()', vous avez besoin de réflexion pour y accéder (et bien sûr vous n'avez pas de chance si un gestionnaire de sécurité est en place). De plus, si le code 'foo()' d'origine fait des appels 'super', cela ne fonctionnerait pas non plus. – Landei

0

Ce n'est pas possible, nous sommes limités à appeler les implémentations de la superclasse uniquement.

+0

(J'ai été trop impressionné par Aarons maintenant supprimé réponse que J'ai effacé le mien deux secondes après avoir posté;) - supprimé même si il ya beaucoup de meilleures réponses disponibles maintenant) –

19

Vous ne pouvez pas - parce que cela romprait l'encapsulation.

Vous êtes en mesure d'appeler la méthode de votre superclasse, car il est supposé que vous savez ce qui brise l'encapsulation dans votre propre classe , et éviter que ... mais vous ne savez pas quelles règles votre superclasse est l'application - de sorte que vous ne peut pas contourner une implémentation là.

+0

Odd .. Je me souviens qu'il y avait un moyen d'appeler Object.toString() même si toString() était surchargé par une superclasse. Mais 'Type.this' ne compile pas. : -/ –

+1

@Aaron: Je ne suis pas sûr de Object.toString() - pensiez-vous à 'System.identityHashCode'? –

+0

Jamais utilisé ça, je suis à peu près sûr que c'était toString(). Object.super.toString() ne fonctionne pas non plus. Peut-être que c'était un bug dans une version Java précoce ou quelque chose. –

3

Vous ne pouvez pas le faire de manière simple.

C'est ce que je pense que vous pouvez faire:

Avoir un bool dans votre classe B. Maintenant, vous devez appeler foo de B de C comme [super foo], mais avant de le faire régler la bool true. Maintenant, dans B foo vérifier si le booléen est vrai alors n'exécutez aucune étape dans cela et appelez juste foo de A.

Espérons que cela aide.

+6

C'est le bidouillage Java le plus fou de tous les temps :) –

+2

La réponse de Jon Skeet est la meilleure: ce type de fonctionnalité ne doit pas être activé car il casse l'encapsulation. Au lieu d'adresser le _HOW_ pour faire quelque chose comme ceci, nous devrions adresser le _WHY_ n'importe qui voudrait faire quelque chose comme ceci (et déchirer cet argument pour violer les principes de POO). – polygenelubricants

+2

@Nikita Rybak: Les gens demandent des choses qui ne devraient pas être posées. D'où les réponses qui ne devraient pas être données;) –

0

I smell quelque chose de louche ici. Etes-vous sûr de ne pas pousser trop loin l'enveloppe "simplement parce que vous devriez être capable de le faire"? Êtes-vous sûr que c'est le meilleur modèle de conception que vous pouvez obtenir? Avez-vous essayé de le refactoriser?

0

J'ai eu un problème où une superclasse appellerait une méthode de classe supérieure qui a été surchargée. C'était ma solution de contournement ...

// CE échouerait MÉTHODES D'APPELER superclasse a1() invoquerait classe supérieure MÉTHODE

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(); 
} 

// CE consacre le droit CLASSES méthodes sont appelées // les méthodes publiques Seules les méthodes privées et sont donc les méthodes publiques peuvent être remplacées sans affecter les fonctionnalités de la superclasse.

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(); 
} 

J'espère que cela aide. :)

+0

cela ne répond pas réellement à la question. s'il vous plaît relisez la question. – Aboutblank

0

Avant d'utiliser l'API de réflexion, pensez à son coût.

C'est simplement facile à faire. Par exemple:

C sous-classe de la sous-classe B et B de A. Les deux ont la méthode methodName() par exemple.

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"); 
    } 

} 

Run classe C sortie sera: Classe A Classe C

lieu de sortie: classe A Classe B Classe C

2

Pour citer une réponse précédente « Vous pouvez » t - parce que cela briserait l'encapsulation. " à laquelle je voudrais ajouter que:

Cependant, il existe un cas de coin où vous pouvez, à savoir si la méthode est static (public ou protected). Vous ne pouvez pas overwrite the static method. Avoir une méthode public static est trivial pour prouver que vous pouvez en effet le faire. Pour protectedprotectedprotected Cependant, vous avez besoin de l'intérieur de l'une de vos méthodes pour effectuer une conversion à n'importe quelle super-classe dans le chemin d'héritage et cette méthode de super-classe serait appelée.

Tel est le cas de coin j'explore dans ma réponse:

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 réponse reste encore Non, mais je voulais juste montrer un cas où vous pouvez, bien qu'il ne serait probablement pas de sens et est juste un exercice.

2

Oui, vous pouvez le faire. C'est un hack. Essayez de ne pas concevoir votre programme comme ça.

class A 
{ 
    public void method() 
    { /* Code specific to A */ } 
} 

class B extends A 
{ 
    @Override 
    public void method() 
    { 
     //compares if the calling object is of type C, if yes push the call to the A's method. 
     if(this.getClass().getName().compareTo("C")==0) 
     { 
      super.method(); 
     } 
     else{ /*Code specific to B*/ } 

    } 
} 

class C extends B 
{ 
    @Override 
    public void method() 
    { 
     /* I want to use the code specific to A without using B */ 
     super.method(); 

    } 
} 
+0

Ceci est appelé Inversion of Control! –