46

Let's say I have three classes A, B and C.

  • B extends A
  • C extends B

All have a public void foo() method defined.

Now from C's foo() method I want to invoke A's foo() method (NOT its parent B's method but the super super class A's method).

I tried super.super.foo();, but it's invalid syntax. How can I achieve this?

Boann
  • 48,794
  • 16
  • 117
  • 146
Harish
  • 7,589
  • 10
  • 36
  • 47
  • 1
    Just because someone should ask, why does C extend B if you seem to want it to extend A directly? (I imagine there are other parts you're relying on B's functionality for, or something) – Tim Stone Aug 11 '10 at 07:46
  • A's foo() can be called from C using super.foo() only if B doesn't override A's foo(). – YoK Aug 11 '10 at 08:02
  • 1
    _Effective Java 2nd Edition, Item 16: Favor composition over inheritance_. Also, check out the decorator pattern; it may suit your need better. – polygenelubricants Aug 11 '10 at 08:47
  • 3
    possible duplicate of [Why is super.super.method(); not allowed in Java?](http://stackoverflow.com/questions/586363/why-is-super-super-method-not-allowed-in-java) – Damien MATHIEU Apr 08 '13 at 20:32

12 Answers12

41

You can't even use reflection. Something like

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

would lead to an InvocationTargetException, because even if you call the foo-Method on the superSuperClass, it will still use C.foo() when you specify "this" in invoke. This is a consequence from the fact that all Java methods are virtual methods.

It seems you need help from the B class (e.g. by defining a superFoo(){ super.foo(); } method).

That said, it looks like a design problem if you try something like this, so it would be helpful to give us some background: Why you need to do this?

Landei
  • 54,104
  • 13
  • 100
  • 195
  • 2
    It was not my requirement. I was just thinking out of my head all possibilites of playing around with inheritance and got this question. Thanks.. I got the answer – Harish Aug 19 '10 at 06:18
  • Well I need to do that because the super class overrides the super super class in a way I don't want.. and it is a library... so I want to call the one from super super class... maybe taking the source code of the method of the super super class and overriding again solves this? – xdevs23 Mar 15 '16 at 15:43
  • Of course you can write in your method what you want, so in this case copying the code should work. However, if the super-super-class uses private or package private fields or methods in `foo()`, you need reflection to access these (and of course you are out of luck if a security manager is in place). Further, if the original `foo()` code makes `super` calls itself, it wouldn't work either. – Landei Mar 16 '16 at 16:56
23

You can't - because it would break encapsulation.

You're able to call your superclass's method because it's assumed that you know what breaks encapsulation in your own class, and avoid that... but you don't know what rules your superclass is enforcing - so you can't just bypass an implementation there.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Odd.. I remember that there was a way to call Object.toString() even if toString() was overloaded by a superclass. But `Type.this` doesn't compile. :-/ – Aaron Digulla Aug 11 '10 at 07:34
  • 2
    @Aaron: I'm not sure about Object.toString() - were you thinking of `System.identityHashCode`? – Jon Skeet Aug 11 '10 at 07:35
  • 1
    Never used that, I'm pretty sure that it was toString(). Object.super.toString() doesn't work either. Maybe it was a bug in an early Java version or something. – Aaron Digulla Aug 11 '10 at 07:39
3

You can't do it in a simple manner.

This is what I think you can do:

Have a bool in your class B. Now you must call B's foo from C like [super foo] but before doing this set the bool to true. Now in B's foo check if the bool is true then do not execute any steps in that and just call A's foo.

Hope this helps.

Madhup Singh Yadav
  • 8,110
  • 7
  • 51
  • 84
  • 6
    That's the wildest Java hack ever :) – Nikita Rybak Aug 11 '10 at 07:40
  • 2
    Jon Skeet's answer is best: this kind of functionality should not be enabled because it breaks encapsulation. Instead of addressing the _HOW_ to do something like this, we should address the _WHY_ would anyone even want to do something like this (and tear apart that argument for violating OOP principles). – polygenelubricants Aug 11 '10 at 07:41
  • 2
    @Nikita Rybak: People ask for things that should not be asked. Hence the answers that should not be given ;) – Madhup Singh Yadav Aug 11 '10 at 07:42
  • @polygenelubricants : I am not challenging Skeet's answer. I do not dare too. I just gave my view point. – Madhup Singh Yadav Aug 11 '10 at 07:44
  • 2
    It would seem to be thread unsafe. If you are going to do something like this you can put void foo ( boolean flag ) { if ( flag ) super . foo ( ) ; else this . foo ( ) ; } in class B. As for encapsulation, once you come up with some reason why class B should have a foo(boolean) method, then how it is implemented is an implementation detail. – emory Aug 11 '10 at 07:49
2

To quote a previous answer "You can't - because it would break encapsulation." to which I would like to add that:

However there is a corner case where you can,namely if the method is static (public or protected). You can not overwrite the static method.

Having a public static method is trivial to prove that you can indeed do this.

For protected however, you need from inside one of your methods to perform a cast to any superclass in the inheritance path and that superclass method would be called.

This is the corner case I am exploring in my answer:

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

The answer remains still No, but just wanted to show a case where you can, although it probably wouldn't make any sense and is just an exercise.

Community
  • 1
  • 1
Radu Ionescu
  • 3,462
  • 5
  • 24
  • 43
2

Yes you can do it. This is a hack. Try not to design your program like this.

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

    }
}
Jainam MJ
  • 301
  • 4
  • 11
1

There is a workaround that solved my similar problem:

Using the class A, B, and C scenario, there is a method that will not break encapsulation nor does it require to declare class C inside of class B. The workaround is to move class B's methods into a separate but protected method.

Then, if those class B's methods are not required simply override that method but don't use 'super' within that method. Overriding and doing nothing effectively neutralises that class B method.

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

The result will be:

callMe for A
callMe for C
Ray2U
  • 31
  • 2
1

This is not something that you should do normally but, in special cases where you have to workaround some bug from a third party library (if it allow to do so), you can achieve calling a super super class method that has already been overwritten using the delegation pattern and an inner class that extends the super super class to use as a bridge:

class A() {
  public void foo() {
    System.out.println("calling A");
  }
}

class B extends A() {
  @Overwrite
  public void foo() {
    System.out.println("calling B");
  }
}

class C extends B() {
  private final a;

  public C() {
    this.a = new AExtension();
  }

  @Overwrite
  public void foo() {
    a.foo();
  }

  private class AExtension extends A {
  }
}

This way you will be able to not only call the super super method but also combine calls to other super super class methods with calls to methods of the super class or the class itself by using `C.super` or `C.this`. 
teoincontatto
  • 1,565
  • 1
  • 9
  • 8
0

I had a problem where a superclass would call an top class method that was overridden. This was my workaround...

//THIS WOULD FAIL CALLING SUPERCLASS METHODS AS a1() would invoke top class METHOD

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

//THIS ENSURES THE RIGHT SUPERCLASS METHODS ARE CALLED //the public methods only call private methods so all public methods can be overridden without effecting the superclass's functionality.

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

I hope this helps. :)

Penny
  • 31
  • 4
0

Before using reflection API think about the cost of it.

It is simply easy to do. For instance:

C subclass of B and B subclass of A. Both of three have method methodName() for example.

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 class C Output will be: Class A Class C

Instead of output: Class A Class B Class C

Kristy Welsh
  • 7,828
  • 12
  • 64
  • 106
0

It's not possible, we're limited to call the superclass implementations only.

Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
  • (I was too much impressed by Aarons now deleted answer that I deleted mine two seconds after posting ;) - undeleted it even though there are much better answers available now) – Andreas Dolk Aug 11 '10 at 08:32
0

I smell something fishy here.

Are you sure you are not just pushing the envelope too far "just because you should be able to do it"? Are you sure this is the best design pattern you can get? Have you tried refactoring it?

lorenzog
  • 3,483
  • 4
  • 29
  • 50
0

In my simple case I had to inherit B and C from abstract class, that incapsulates equal methods of B and C. So that

     A
     |
   Abstr
    / \
   B   C

While it doesn't solve the problem, it can be used in simple cases, when C is similar to B. For instance, when C is initialized, but doesn't want to use initializers of B. Then it simply calls Abstr methods.

This is a common part of B and C:

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

    public void hideProgress() {
    }
}

This is B, that has it's own method onCreate(), which exists in 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 shows its own layout:

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();
    }
}
CoolMind
  • 26,736
  • 15
  • 188
  • 224