25

Lets say that we have the following code:

class A {

    public void doLogic() {
        System.out.println("doLogic from A");
    }
}

class B extends A {

    @Override
    public void doLogic() {
        System.out.println("doLogic from B");
    }

    public void doDifferentLogic() {
        System.out.println("doDifferentLogic from B");
        super.doLogic();
    }
}

class C extends B {

    @Override
    public void doLogic() {
        System.out.println("doLogic from C");
    }
}

public class Test {

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

When we execute this code the expected behavior is the following: Since c holds a reference to object of class C, when you invoke the c.doDifferentLogic() method the JVM searches for the method in the C class and since it is not found it starts looking at the inheritance tree. As expected the doDifferentLogic() method is found in the super class and executed. However the construct super.doLogic() is expected to look from the current reference "Point of View", which is of type C. So the super of C should B, but instead the method from the top class A is invoked.

If you remove the super keyword, or replace it with the this keyword (which is the same as "this" is implicit), you get the expected polymorphic behavior and the doLogic() from C class is invoked.

So my question is: Should call to super.doLogic() be this.super.doLogic()(2), instead of static.super.doLogic()(1) ?

Both are invalid constructs, they are here just to try to explain myself better.

(1)or in other words - from the reference to the current object c , get the superclass of the current object and invoke the doLogic() method instead of (2)from this class get the superclass and invoke its doLogic() method ?

  • 1
    Is there an instance where this would happen as described, or why would you want it to happen that way? Wouldn't it risk a sub class of B accidentally/implicitly modifying the implementation of B.doDifferentLogic()? – CLo Feb 26 '14 at 21:34
  • If I understand you question properly you are asking if it is bad design to have call to public method from within other public method in your class - yes it is. If you want to guarantee that the doDifferentLogic() always behave the same in the subclasses you should make the doLogic() private and if you want to make both method public you should call the private method from within the public method like this: @Override public void doLogic() { doPrivateLogic() } private void doPrivateLogic() { System.out.println("doLogic from B"); } – Антон Антонов Feb 27 '14 at 08:10

3 Answers3

50

In Java, the super keyword always refers to the superclass of the type in which the keyword is used, not the superclass of the dynamic type of the object on which the method is invoked. In other words, super is resolved statically, not dynamically. This means that in the context of class B, the super keyword always refers to class A, regardless of whether the B method is executed using a C object as the receiver. To the best of my knowledge, there isn't a way to dynamically determine the superclass type and use its methods without using reflection.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 4
    Just to add to this excellent answer, when referring to a method defined on a base class, the call `super.doLogic()` will walk up the inheritance hierarchy until it finds a concrete implementation of the `doLogic()` method to execute. – Brian Driscoll Feb 26 '14 at 17:31
  • 1
    Here's the relevant JLS Section: [Section 15.11.2](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.11.2). – rgettman Feb 26 '14 at 17:33
  • 1
    Just want to clarify on Brian's comment, the lookup for the super implementation is not performed statically by the compiler. It is a dynamic lookup performed by the VM that always start's from the direct parent class of the class to which the method with the super call belongs. [This behaviour was changed in Java 1.1](http://stackoverflow.com/questions/8949933/what-is-the-purpose-of-the-acc-super-access-flag-on-java-class-files/8950564#8950564). – x4u Feb 27 '14 at 00:25
4

Here is where the JLS defines this specifically:

  • If the form is super . NonWildTypeArgumentsopt Identifier, then the name of the method is the Identifier and the class to be searched is the superclass of the class whose declaration contains the method invocation.

So Java considers super as referring to the superclass of the class enclosing the super.method call, not the actual run time type.

Radiodef
  • 37,180
  • 14
  • 90
  • 125
1

Whenever the super.doLogic() from classB is executed, it will always refer to the doLogic() method of the super class of classB which in this case would be classA. This is the desired behavior so that control does not keep passing between classes within the same method. This is the concept of a class context. Once you are in the context of a class, you will have to follow the rules established by that class and not keep passing control between different contexts.

ucsunil
  • 7,378
  • 1
  • 27
  • 32
  • But if this is true, the call to this.doLogic(); in class B, should call the method in class B, instead it calls the method in class C, when the object is from class C. Which is actually jump to B class find the method there and then start over from the reference ? – Антон Антонов Feb 26 '14 at 17:34