Вызов метода супер супер класса - PullRequest
34 голосов
/ 11 августа 2010

Допустим, у меня есть три класса A, B и C.

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

Все имеют public void foo() метод определен.

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

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

Ответы [ 11 ]

31 голосов
/ 11 августа 2010

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

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

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

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

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

20 голосов
/ 11 августа 2010

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

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

3 голосов
/ 11 августа 2010

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

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

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

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

2 голосов
/ 09 июля 2017

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

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 голосов
/ 20 февраля 2016

Цитировать предыдущий ответ: «Вы не можете - потому что это нарушит инкапсуляцию». к которому я хотел бы добавить следующее:

Однако есть угловой случай, когда вы можете, а именно, если метод 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
    }
}

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

0 голосов
/ 11 июня 2019

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

Используя сценарии классов A, B и C, существует метод, который не нарушает инкапсуляцию и не требует объявления класса C внутри класса.Б. Обходной путь - переместить методы класса 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's 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
0 голосов
/ 26 декабря 2018

В моем простом случае мне пришлось наследовать 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();
    }
}
0 голосов
/ 16 февраля 2015

Прежде чем использовать 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 будет: Класс А Класс С

Вместо вывода: Класс А Класс б Класс С

0 голосов
/ 16 апреля 2013

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

// ЭТО БЫЛ СВОБОДНЫМ ВЫЗОВОМ МЕТОДОВ СУПЕРКЛАССА AS 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();
 }

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

0 голосов
/ 11 августа 2010

Я запах что-то подозрительное здесь.

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

...