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:
Default super-constructor calls, and
Instance initializers relative to super calls, and
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:
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 value0
.The JVM calls
Sub1
.Sub1
immediately callssuper()
(Super1
), which......calls
printThree
. SinceprintThree
is overridden, even though the call to it is in the code forSuper1
, it's the overridden method (the one inSub1
) that gets called. This is part of how Java implements polymorphism. Sincethree
's instance initializer hasn't been run yet,three
contains0
, and that's what gets output.Super1
returns.
Back in
Sub1
, the instance initializer code forthree
that the compiler inserted (relocated, really) runs and givesthree
a new value.Sub1
callsprintThree
. Sincethree
's instance initializer code has now run,printThree
prints3
.
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:
- Do not use anything from the superclass definition and rewrite it in a completely new way.
- 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 Overriding
s 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 Overriding
s 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
In Java, How to Define an Integer Constant in Binary Format
Closing Bufferedreader and System.In
How Do Java Method Annotations Work in Conjunction with Method Overriding
How to Enable Anti Aliasing in Arbitrary Java Apps
How to "Add" to Classpath Dynamically in Java
Things Possible in Intellij That Aren't Possible in Eclipse
Can a Class Have No Constructor
Transactional Saves Without Calling Update Method
Differencebetween Putting a Property on Application.Yml or Bootstrap.Yml in Spring Boot
Convert .Jar to an Osx Executable
@Onetomany List<> VS Set<> Difference
Compareto with Primitives -> Integer/Int
Running Java Gives "Error: Could Not Open 'C:\Program Files\Java\Jre6\Lib\Amd64\Jvm.Cfg'"