1

Having the following superclass:

public class SuperClass {

    protected Integer a;
    protected Integer b;
    
    public void doSomething() {
        this.a = 10;
    }
    
    public void doEverything() {
        SuperClass.this.doSomething();
        this.b = 20;
    }
    
    public static void main(String[] args) {
        SuperClass instance = new SubClass();
        instance.doEverything();
        System.out.println(instance.a); //should print 10
        System.out.println(instance.b);
    }
}

And the following subclass:

public class SubClass extends SuperClass {

    @Override
    public void doSomething() {
        super.doSomething();
        super.a *= 10;
    }

    public void doEverything() {
        super.doEverything();
        this.b += 5;
    }
}

Outputs:

100

25

So, SuperClass.this.doSomething(); is accessing SubClass's doSomething, but I need it to access the SuperClass's doSomething. In that case, I don't have the super keyword, because I'm already on super!

  1. Is there a way to reference¹ the deep SuperClass.this.doSomething, so it would output 10 for the first output value?

    ¹ I'm interested on referencing: we could, of course, extract the SuperClass's doSomething to an auxiliar private method and access it directly.

  2. If there is no way, does the situation where a superclass method needing to access its another (although overridden) method mean that my OOP design isn't correct? Why?

Community
  • 1
  • 1
falsarella
  • 12,217
  • 9
  • 69
  • 115
  • possible duplicate of [how to call the overridden method of superclass](http://stackoverflow.com/questions/15668032/how-to-call-the-overridden-method-of-superclass) – fabian Apr 10 '15 at 18:43
  • @fabian *Thinking on OOP, shouldn't a superclass be able to access its own (although overridden) method?* - I think that question wasn't answered there: I saw that answer when I as writting my question, but it didn't hit that point. – falsarella Apr 10 '15 at 18:52
  • 1
    To prevent polymorphism (dynamic binding - based on actual type of `this` instance) you would need to either make your method `private`, `static` or `final`. But `final` means no overridden method in derived class; `private` means that original method will not be accessible in derived class (and you will also not be able to override it despite being able to create method with same signature). Maybe what you are looking for is some kind of `static` approach? – Pshemo Apr 10 '15 at 18:53
  • @Pshemo You can't override a static method, only hide it. No `super`. It also can't refer to `this`. – RealSkeptic Apr 10 '15 at 18:54
  • @falsarella I don't really get your point when you say "Thinking on OOP". One key feature of OOP is the ability to override methods, but you're trying to subvert that. – Paul Boddington Apr 10 '15 at 18:57
  • 1
    So as you see, you can't do what you want. Even reflection will invoke code based on actual type of instance. – Pshemo Apr 10 '15 at 18:58
  • @pbabcdefp Am I? I am just trying to call `super` being on the super! You are telling that `super.doSomething();` is subverting OOP? – falsarella Apr 10 '15 at 19:14
  • @pbabcdefp [It appears that c++ enables you to do what I want](http://stackoverflow.com/a/29568622/1064325). Are you telling that c++ is subverting OOP? – falsarella Apr 10 '15 at 19:15
  • @falsarella No I'm not. `super.doSomething()` has a purpose. `super.doSomething()` is used to add functionality to the method. E.g. `void doSomething() { super.doSomething(); System.out.println("Something done!"; }`. What you're trying to do doesn't have a purpose. You even mention the solution in the question. – Paul Boddington Apr 10 '15 at 19:17
  • 1
    @falsarella Also remember that `super.doSomething()` is needed because often you will not have control over the super class, but you would always have control over `this` class. I don't know anything about C++ so can't comment on that. Maybe they considered allowing this, but just decided against it as there is a workaround already. I wish James Gosling was here to tell us! – Paul Boddington Apr 10 '15 at 19:27
  • possible duplicate of [Disallow subclasses from overriding Java method](http://stackoverflow.com/questions/13021472/disallow-subclasses-from-overriding-java-method) – Joe Apr 11 '15 at 07:02

4 Answers4

3

I assume you come to Java from C++ background. The languages are similar in concepts and in syntax, but they are different in the implementation.

You can achieve what I think is your intention also in Java, but the structure will look differently from C++.

In Java the construct SuperClass.this in your example is exactly the same as this, so SuperClass.this.doSomething(); is exactly what just doSomething() would be. So why does Java at all has the construct SuperClass.this? It has its meaning unrelated to the inheritance. It is useful in the context of nested classes.

Imagine a structure like this:

class A {
    class B {
        public void doSomething() {
         // this here refers to an instance of the class B
         System.out.println(this);
         // We need to write is this way,
         // because this hides the this reference to the instance of A.
         // A.this is the instance of A where this is nested
         System.out.println(A.this); 
     }
}

So how can you make sure to be able to have a method in a class that subclasses can override, and still be able to call the specific implementation?

Well, in the strict sense, you cannot. What you can do, is to create a final method, which cannot be overridden, and call it from a non-final method.

class SuperClass {
    public void doSomething() {
        doSuperClassyThing();
    }

    public final void doSuperClassyThing() { // cannot be overridden
        ...
    }
}

A similar approach (with a bit different goal) you can see in the Template Method Pattern.

falsarella
  • 12,217
  • 9
  • 69
  • 115
Gregor Raýman
  • 3,051
  • 13
  • 19
  • Nice answer. Thanks for coming with the inner class approach. – falsarella Apr 27 '15 at 23:53
  • While it was the most informative answer so far, I'm accepting it =] Btw, [I just discovered new possibilities](http://stackoverflow.com/a/29908146/1064325) after the reading I had here. Thanks! – falsarella Jun 29 '15 at 19:42
2

The answer is that you can't refer to it. The only way to do this is the private helper method approach that you are aware of already.

If you want to know the reason why, I guess it's just because it would complicate the language for no reason; you can always get the same result by using a private helper method. The syntax SuperClass.this.doSomething() is already taken for something else. That means calling the method doSomething on the enclosing instance if SuperClass is an enclosing class.

Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
2

You cannot do what you want. The way polymorphism works is by doing what you are seeing.

That means there is no direct way to call SuperClass.doSomething() from SuperClass.doSomething() without going though SubClass.doSomething() unless you're working with an actual instance of SuperClass.

In some other languages you have power to tell how to handle this for example with keyword virtual in c++, but in java you don't have that option. All the method are being dynamically binded so you cannot do that. You can only not override or prevent it from being overriden at all.

notanormie
  • 435
  • 5
  • 20
  • *If there is no way, thinking on OOP, shouldn't a superclass be able to access its own (although overridden) method?* – falsarella Apr 10 '15 at 18:50
  • Hmm, it appears that it is Java that doens't support that then. Nice to know that other languages like C++ does. – falsarella Apr 10 '15 at 19:17
1

If you ever find yourself on that situation, maybe you should rethink and consider that the class structure is not that correct yet.

Try to implement one of the following approaches:

  1. Composition over Inheritance.
  2. Creating a new Inheritance level (a class in the middle that has a reference to super).
  3. Same as (2.), but using an inner class.
  4. Extract the wanted method to a separate private one and call it where applicable.

Since (1.) wouldn't be as dry as the others, (4.) leaves a feeling of a workaround, and (2.) would require the creation of a new file and would reference outside SuperClass; I think the closest approach would be (3.), which is the only solution that in some way references super inside SuperClass (although it's actually referenced on a SuperClass inner class):

SuperClass.java:

public abstract class SuperClass {

    protected Integer a;
    protected Integer b;

    public void doSomething() {
        this.a = 10;
    }

    public abstract void doEverything();

    public static class Impl extends SuperClass {

        @Override
        public void doEverything() {
            super.doSomething();
            this.b = 20;
        }
    }

    public static void main(String[] args) {
        SuperClass instance = new SubClass();
        instance.doEverything();
        System.out.println(instance.a); //prints 10
        System.out.println(instance.b);
    }
}

SubClass.java:

public class SubClass extends SuperClass.Impl {

    @Override
    public void doSomething() {
        super.doSomething();
        super.a *= 10;
    }

    @Override
    public void doEverything() {
        super.doEverything();
        this.b += 5;
    }
}
falsarella
  • 12,217
  • 9
  • 69
  • 115