Подтвердить что ты не робот

Вызов метода супер супер класса

Скажем, у меня есть три класса A, B и C.

  • B расширяет A
  • C расширяет B

У всех есть метод public void foo().

Теперь из метода C foo() я хочу вызвать метод A foo() (НЕ его родительский метод B, но метод супер супер класса A).

Я попробовал super.super.foo();, но это недействительный синтаксис. Как я могу достичь этого?

4b9b3361

Ответ 1

Вы даже не можете использовать отражение. Что-то вроде

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

приведет к InvocationTargetException, потому что даже если вы вызываете foo-Method на superSuperClass, он все равно будет использовать C.foo(), когда вы укажете "this" в invoke. Это связано с тем, что все методы Java являются виртуальными методами.

Кажется, вам нужна помощь из класса B (например, путем определения метода superFoo(){ super.foo(); }).

Тем не менее, это похоже на проблему с дизайном, если вы попробуете что-то вроде этого, поэтому было бы полезно дать нам несколько предпосылок: зачем вам это нужно?

Ответ 2

Вы не можете - потому что он сломает инкапсуляцию.

Вы можете вызвать свой метод суперкласса, потому что он предположил, что вы знаете, что нарушает инкапсуляцию в вашем собственном классе, и избегайте этого... но вы не знаете, какие правила вы используете надкласс, поэтому вы не можете просто обойти реализацию там.

Ответ 3

Вы не можете сделать это простым способом.

Вот что я думаю, что вы можете сделать:

У вас есть bool в вашем классе B. Теперь вы должны вызывать B foo из C как [super foo], но перед этим установите bool в true. Теперь в B foo проверьте, является ли bool истинным, тогда не выполняйте никаких шагов в этом и просто вызывайте A foo.

Надеюсь, что это поможет.

Ответ 4

Чтобы процитировать предыдущий ответ "Вы не можете - потому что он сломает инкапсуляцию". к которому я хотел бы добавить, что:

Однако есть и угловой случай, где вы можете, а именно, если метод static (public или protected). Вы не можете перезаписать статический метод.

Наличие метода public static тривиально, чтобы доказать, что вы действительно можете это сделать.

Однако для protected вам нужно изнутри одного из ваших методов выполнить приведение к любому суперклассу в пути наследования и вызвать метод суперкласса.

Это угловой случай, который я изучаю в своем ответе:

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
    }
}

Ответ по-прежнему остается Нет, но просто хотел показать случай, где вы можете, хотя это, вероятно, не имеет никакого смысла и является просто упражнением.

Ответ 5

Да, вы можете это сделать. Это взломать. Старайтесь не создавать свою программу следующим образом.

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

    }
}

Ответ 6

Это невозможно, мы ограничены только вызовом реализаций суперкласса.

Ответ 7

I smell что-то подозрительное здесь.

Вы уверены, что не слишком сильно нажимаете конверт "только потому, что вы должны это сделать"? Вы уверены, что это лучший дизайн, который вы можете получить? Вы пытались реорганизовать его?

Ответ 8

У меня была проблема, когда суперкласс вызывал метод верхнего класса, который был переопределен. Это было мое решение...

//ЭТО БЫЛО НЕВОЗМОЖНО ВЫЗЫВАТЬ МЕТОДЫ СУПЕРКЛАССА. Как a1() будет ссылаться на метод высшего класса

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

//ЭТО ОБЕСПЕЧИВАЕТ ПРАВАЯ МЕТОДЫ СУПЕРКЛАССА // публичные методы вызывают только частные методы, поэтому все общедоступные методы могут быть переопределены без использования функциональных возможностей суперкласса.

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

Надеюсь, это поможет. :)

Ответ 9

Перед использованием рефлексивного API подумайте о его стоимости.

Это просто сделать. Например:

C подкласса B и B подкласса A. Оба из них имеют метод methodName(), например.

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

}

Выполнить класс C Выход будет: Класс А Класс C

Вместо вывода: Класс А Класс B Класс C

Ответ 10

В моем простом случае мне пришлось наследовать B и C от абстрактного класса, который инкапсулирует равные методы B и C. Так что

     A
     |
   Abstr
    / \
   B   C

Хотя это не решает проблему, его можно использовать в простых случаях, когда C похож на B. Например, когда C инициализируется, но не хочет использовать инициализаторы B. Тогда он просто вызывает методы Abstr.

Это общая часть B и C:

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

    public void hideProgress() {
    }
}

Это B, у которого есть собственный метод onCreate(), который существует в 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 показывает свой собственный макет:

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

Ответ 11

Существует обходной путь, который решил мою похожую проблему:

Используя сценарии классов A, B и C, существует метод, который не нарушает инкапсуляцию и не требует объявления класса C внутри класса B. Обходной путь заключается в перемещении методов класса B в отдельный, но защищенный метод.

Затем, если эти методы класса B не требуются, просто переопределите этот метод, но не используйте "super" в этом методе. Переопределение и бездействие фактически нейтрализуют этот метод класса B.

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

public class B extends A {
    protected void callMe() {
        super.callMe();
        methodsForB(); // Class B methods moved out and into it own method
    }

    protected void methodsForB() {
        System.out.println("methods for B");
    }
}

public class C extends B {

    public static void main(String[] args) {
        new C().callMe();
    }

    protected void callMe() {
        super.callMe();
        System.out.println("callMe for C");
    }

    protected void methodsForB() {
        // Do nothing thereby neutralising class B methods 
    }
}

Результатом будет:

callMe for A
callMe for C