Java: Calling a Super Method Which Calls an Overridden Method

Java: Calling a super method which calls an overridden method

The keyword super doesn't "stick". Every method call is handled individually, so even if you got to SuperClass.method1() by calling super, that doesn't influence any other method call that you might make in the future.

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

You can't even achieve the desired effect using Reflection (see the documentation of java.lang.reflect.Method.invoke(Object, Object...)).

[EDIT] There still seems to be some confusion. Let me try a different explanation.

When you invoke foo(), you actually invoke this.foo(). Java simply lets you omit the this. In the example in the question, the type of this is SubClass.

So when Java executes the code in SuperClass.method1(), it eventually arrives at this.method2();

Using super doesn't change the instance pointed to by this. So the call goes to SubClass.method2() since this is of type SubClass.

Maybe it's easier to understand when you imagine that Java passes this as a hidden first parameter:

public class SuperClass
{
public void method1(SuperClass this)
{
System.out.println("superclass method1");
this.method2(this); // <--- this == mSubClass
}

public void method2(SuperClass this)
{
System.out.println("superclass method2");
}

}

public class SubClass extends SuperClass
{
@Override
public void method1(SubClass this)
{
System.out.println("subclass method1");
super.method1(this);
}

@Override
public void method2(SubClass this)
{
System.out.println("subclass method2");
}
}

public class Demo
{
public static void main(String[] args)
{
SubClass mSubClass = new SubClass();
mSubClass.method1(mSubClass);
}
}

If you follow the call stack, you can see that this never changes, it's always the instance created in main().

What happens if you call an overridden method using super in a constructor

You're seeing the effects of three things:

  1. Default super-constructor calls, and

  2. Instance initializers relative to super calls, and

  3. How overridden methods work

Your Sub1 constructor is really this:

Sub1(){
super(); // <== Default super() call, inserted by the compiler
three=(int) Math.PI; // <== Instance initializers are really inserted
// into constructors by the compiler
super.printThree();
}

(Surprising, I know, but it's true. Use javap -c YourClass to look. :-) )

The reason it looks like that is that the superclass must have a chance to initialize its part of the object before the subclass can initialize its part of the object. So you get this kind of interwoven effect.

And given that that's what Sub1 really looks like, let's walk through it:

  1. The JVM creates the instance and sets all instance fields to their defaults (all bits off). So at this point, the three field exists, and has the value 0.

  2. The JVM calls Sub1.

  3. Sub1 immediately calls super() (Super1), which...

    1. ...calls printThree. Since printThree is overridden, even though the call to it is in the code for Super1, it's the overridden method (the one in Sub1) that gets called. This is part of how Java implements polymorphism. Since three's instance initializer hasn't been run yet, three contains 0, and that's what gets output.

    2. Super1 returns.

  4. Back in Sub1, the instance initializer code for three that the compiler inserted (relocated, really) runs and gives three a new value.

  5. Sub1 calls printThree. Since three's instance initializer code has now run, printThree prints 3.

With regard to this instance initializer code getting moved into the constructor, you might be wondering: What if I have more than one constructor? Which one does the code get moved into? The answer is that the compiler duplicates the code into each constructor. (You can see that in javap -c, too.) (If you have a really complicated instance initializer, I wouldn't be surprised if the compiler effectively turned it into a method, but I haven't looked.)

It's a bit clearer if you do something really naughty and call a method during your instance init: (live copy)

class Super
{
public static void main (String[] args) {
new Sub();
}

Super() {
System.out.println("Super constructor");
this.printThree();
}

protected void printThree() {
System.out.println("Super's printThree");
}
}
class Sub extends Super
{
int three = this.initThree();

Sub() {
this.printThree();
}

private int initThree() {
System.out.println("Sub's initThree");
return 3;
}

protected void printThree() {
System.out.println("Sub's printThree: " + this.three);
}
}

Output:


Super constructor
Sub's printThree: 0
Sub's initThree
Sub's printThree: 3

Note where "Sub's initThree" came in that sequence.

How to call the overridden method of a superclass?

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

Basically a cat always knows it is a cat and will always behave like a cat regardless of if you treat is as a Cat, Felis, Felinae, Felidae, Feliformia, Carnivora, Theria, Mammalia, Vertebrata, Chordata, Eumetazoa, Animalia, Animal, Object, or anything else :-)

Java: Calling superclass' constructor which calls overridden method which sets a field of subclass

class Test2 {
public int number = 0;
}

is equivalent to

class Test2 {
public int number;

public Test2() {
super();
number = 0;
}
}

So through invoking the super constructor the field number is set to 1. After the return from the super constructor, your assignment of number to 0 is executed.

Just remove the assignment and it should behave as you expect.

What is the purpose of calling super class's method while overriding a method?

When you override a method, you redefine the method i.e. if this method is called on the instance of the child class (in which you have overridden the method), this new version of the definition will be called.

When you override a method (i.e. redefine or in other words, replace the superclass definition with the child's version of the definition), you have two choices:

  1. Do not use anything from the superclass definition and rewrite it in a completely new way.
  2. Reuse the superclass definition at some point (in the beginning/middle/end) in the new definition. It's like putting a cherry on the ice cream cone where ice cream cone is the superclass definition of the method and cherry is added in the new definition.

Note that as already pointed out by Andy Turner, a requirement to call super is considered an antipattern.

How to call the superclass implementation of an overridden method from inside the superclass in Java?

You could move said method body to a private method and let the default method (the one which may be overridden by the subclass) delegate to the former. See this example

public abstract class SuperClass {

private Object field1;

protected SuperClass(Object obj){
// call the safe implementation
setField1Safe(obj);
}

public void setField1(Object obj){
// just delegates
setField1Safe(obj);
}

private void setField1Safe(Object obj){
// perform some check on obj and
// then set field1 such that field1==obj
}
}

public class SubClass extends SuperClass{
public SubClass(Object obj){
super(obj);
}

@Override
public void setField1(Object obj){
super.setField1(obj);
// do some work that is necessary only when
// field1 is set through SubClass.setField1()
}
}

That way the sub class can still override setField1 but if you really depend on the implementation then you can call the private setField1Safe method.

Using super.method() when you're not overriding the method?

The leading question is easy to answer:

Is it common practice to always use super for calling methods out of the superclass, even when I'm NOT overriding the method?

No, its not common practice. On the contrary, its dangerously confusing to do so. You call methods normally, because the main point of inheritance is to allow the classes to override methods to change/extend their behavior. You normally don't care about at which level a method is actually implemented.

The obvious exception is when you do override the method yourself and you want/need the parents functionality.

Now to the dangerously confusing part of explicitly calling super:

public class CallSuper {

static class Parent {
public void foo() {
System.out.println("Parent.foo");
}

/**
* Calls foo to do the main work
*/
public void bar() {
System.out.print
foo();
}
}

static class Child extends Parent {
public void foo() {
System.out.println("Child.foo");
}

public void bar() {
super.foo();
}
}

static class GrandChild extends Child {
public void foo() {
System.out.println("GrandChild.foo");
}
}

public static void main(String[] args) {
Parent p = new Parent();
Parent c = new Child();
Parent g = new GrandChild();

System.out.print("Parent.foo() = ");
p.foo();
System.out.print("Child.foo() = ");
c.foo();
System.out.print("GrandChild.foo() = ");
g.foo();

System.out.print("Parent.bar() = ");
p.bar();
System.out.print("Child.bar() = ");
c.bar();
System.out.print("GrandChild.bar() = ");
g.bar();
}
}

If you run this example it will output (added line numbers for clarity):

1 Parent.foo() = Parent.foo
2 Child.foo() = Child.foo
3 GrandChild.foo() = GrandChild.foo
4 Parent.bar() = Parent.foo
5 Child.bar() = Parent.foo
6 GrandChild.bar() = Parent.foo

The first four lines are not surprising, we get what foo implements at each level, respectively Parents's bar calling its foo. It starts to get odd at line 5. Child bypasses its own override of foo by calling super.bar(), so while its foo() is specialized, bar() is not. In Line 6, you see that GrandChild inherits this oddity from Child, so the somewhat innocent looking super.foo() in Child's bar has now broken GrandChild's expectations that its override of foo() is effective for all bar() as well.

Now if you imagine foo() and bar() actually doing something useful and that they have a meaningful relationship with each other, e.g. you are led to believe (either by Parent's documentation or just common sense) that overriding foo() will change the behavior of bar(), too. Child's "super" is breaking that.

As a rule of thumb, if you see a "super.x()" call anywhere outside of an actual override of "x()", its probably an accident lurking to happen.

When NOT to call super() method when overriding?

By calling the super method, you're not overriding the behavior of the method, you're extending it.

A call to super will perform any logic the class you're extending has defined for that method. Take into account that it might be important the moment when you call super's implementation in your method overriding. For instance:

public class A { 
public void save() {
// Perform save logic
}
}

public class B extends A {
private Object b;
@Override
public void save() {
super.save(); // Performs the save logic for A
save(b); // Perform additional save logic
}
}

A call to B.save() will perform the save() logic for both A and B, in this particular order. If you weren't calling super.save() inside B.save(), A.save() wouldn't be called. And if you called super.save() after save(b), A.save() would be effectively performed afterwards B.save().

If you want to override super's behavior (that is, fully ignore its implementation and provide it all yourself), you shouldn't be calling super.

In the SAXParser example you provide, the implementations of DefaultHandler for those methods are just empty, so that subclasses can override them and provide a behavior for those methods. In the javadoc for this method this is also pointed out.

public void startElement (String uri, String localName,
String qName, Attributes attributes) throws SAXException {
// no op
}

About the super() default call in code generated by IDEs, as @barsju pointed out in his comment, in each constructor there's an implicit call to super() (even if you don't write it in your code), which means, in that context, a call to super's default constructor. The IDE just writes it down for you, but it would also get called if you removed it. Also notice that when implementing constructors, super() or any of its variants with arguments (i.e. super(x,y,z)) can only be called at the very beginning of the method.

Call overridden method of super class

i think this will fulfil your requirement!! try this
when you call obj2.printHello(); execution will move to Overridings printHello() and in that method i ve used super.printHello(); this means first invoke super class's printHello() and compiler prints Print Hello then execution again come to Overridings printHello() and print NO NO PRINT HI

class OverrideSuper {
public void printHello() {
System.out.println("Print Hello");
}
}
public class Overriding extends OverrideSuper {
public void printHello() {
super.printHello();
System.out.println("NO NO PRINT HI");
}

public static void main(String[] args) {
// OverrideSuper obj1 = new OverrideSuper();
Overriding obj2 = new Overriding();
obj2.printHello();// this calls printHello() of class Overriding.
// I want to call printHello() of OverrideSuper using obj2. How do I do
// that???
}
}

output

Print Hello
NO NO PRINT HI


Related Topics



Leave a reply



Submit