web-dev-qa-db-fra.com

Appel de la méthode super super class

Disons que j'ai trois classes A, B et C.

  • B étend A
  • C étend B

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

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

J'ai essayé super.super.foo();, mais c'est une syntaxe invalide . Comment puis-je y parvenir?

34
Harish

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

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

mènerait à une InvocationTargetException, car même si vous appelez la méthode foo sur la superSuperClass, il utilisera toujours C.foo() lorsque vous spécifiez "this" 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 de l’aide de la classe B (par exemple, en définissant une méthode superFoo(){ super.foo(); }).

Cela dit, si vous essayez quelque chose comme cela ressemble à un problème de conception, il serait donc utile de nous donner quelques informations de base: Pourquoi vous devez le faire?

31
Landei

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

Vous pouvez appeler la méthode de votre super-classe car elle suppose que vous sachiez ce qui casse l'encapsulation dans votre classe own et que vous évitiez cela ... mais vous ne savez pas quelles règles votre super-classe applique - vous pouvez donc ' t simplement contourner une implémentation ici.

20
Jon Skeet

Vous ne pouvez pas le faire d'une manière simple.

Voici ce que je pense que vous pouvez faire:

Ayez un bool dans votre classe B. Maintenant, vous devez appeler le foo de B depuis C comme [super foo], mais avant cela, définissez bool sur true. Maintenant, dans B's Foo, vérifiez si la valeur booléenne est vraie, alors n’exécutez aucune étape et appelez simplement A's Foo.

J'espère que cela t'aides.

3
Madhup Singh Yadav

Oui tu peux 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();

    }
}
2
Jainam MJ

Pour citer une réponse précédente "Vous ne pouvez pas - parce que cela casserait l’encapsulation." à quoi j'aimerais ajouter que:

Toutefois, vous pouvez le faire dans un cas de figure, à savoir si la méthode est static (public ou protected). Vous ne pouvez pas écraser la méthode statique .

Avoir une méthode public static est trivial pour prouver que vous pouvez le faire.

Cependant, pour protected, vous devez utiliser l'une de vos méthodes pour effectuer un transtypage vers n'importe quelle superclasse du chemin d'héritage et cette méthode sera appelée.

C’est le cas que 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 toujours non, mais je voulais juste montrer un cas où vous pouvez, bien que cela n’aurait probablement aucun sens et qu’il s’agit simplement d’un exercice.

2
Radu Ionescu

Avant d’utiliser l’API de réflexion, réfléchissez-en au coût.

C'est simplement facile à faire. Par exemple:

C sous-classe de B et B sous-classe de A. Les deux des trois ont method 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");
  }

}

Exécuter la classe C La sortie sera: Classe A Classe C

Au lieu de la sortie: Classe A Classe B Classe C

0
user2490562

Dans mon cas simple, je devais hériter de B et C de la classe abstraite, ce qui correspond à des méthodes égales de B et C.

     A
     |
   Abstr
    / \
   B   C

Bien que cela ne résolve pas le problème, il peut être utilisé dans des cas simples, lorsque C est similaire à B. Par exemple, lorsque C est initialisé, mais ne veut pas utiliser les initialiseurs de B. Il appelle simplement les méthodes Abstr.

Ceci est une partie commune de B et C:

public abstract class Abstr extends AppCompatActivity {
    public void showProgress() {
    }

    public void hideProgress() {
    }
}

C'est B, qui a sa propre méthode onCreate(), qui existe dans AppCompatActivity:

public class B extends Abstr {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); // Call from AppCompatActivity.
        setContentView(R.layout.activity_B); // B shows "activity_B" resource.
        showProgress();
    }
}

C montre sa propre mise en page:

public class C extends Abstr {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); // Call from AppCompatActivity.
        setContentView(R.layout.activity_C); // C shows "activity_C" resource.
        showProgress();
    }
}
0
CoolMind

J'ai eu un problème lorsqu'une super-classe appelait une méthode de classe supérieure qui était surchargée . C'était ma solution de contournement ...

// CECI CESSERA D'APPELER SUR LES MÉTHODES SUPERCLASS COMME a1 () invoquerait la méthode top class

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

// CECI ASSURE QUE LES MÉTHODES DE SUPERCLASSES DROITES SONT APPELÉES. Les méthodes publiques appellent uniquement des méthodes privées pour que toutes les méthodes publiques puissent ê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 ça aide.:)

0
Penny

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

0
Andreas_D

Je sens quelque chose de louche ici.

Etes-vous sûr de ne pas trop pousser l'enveloppe "simplement parce que vous devriez pouvoir le faire"? Etes-vous sûr que c'est le meilleur modèle de design que vous puissiez obtenir? Avez-vous essayé de le refactoriser? 

0
lorenzog