The terribly misunderstood super()
For developers new to Java,
here’s a tip that could make you look
more like a ninja coder than colleagues who have been writing Java for years:
learn how
super()
works within constructors.
I say this because
I recently completed a yearlong project with 12 developers
and found during the staffing process that about one third of the developers
I interviewed,
many of whom had been coding Java professionally for years,
misunderstood fundamental concepts of Java object creation.
Some of these smart developers would insist during the job interview that unless a Java
constructor explicitly invokes
super()
,
the parent constructor would never be called.
With such an important Java language feature being so terribly misunderstood,
I thought I’d dust off this blog with a reminder to those new to Java of how
super()
works in constructors.
A related topic would be how
this(...)
works,
but I’ll leave that for another time.
Rule:
You never,
ever,
have to call the no-argument
super()
.
Corollary: It is impossible to instantiate an object without at least one constructor being invoked in all parent classes.
With this rule in mind, here is code to illustrate.
public class A {
public A() {
System.out.println("A says hello");
}
}
public class B extends A {
public B() {
System.out.println("Hello from B");
}
}
If you instantiate class
B
like this:
B myB = new B();
the console will output:
A says hello Hello from B
Since
B
’s
constructor didn’t specify a different constructor in class
A
by using
super
with an argument list,
the Java runtime invoked
A
’s
no-argument constructor by default.
No call to
super()
is needed from within
B
’s
constructor in order for the
A
parent class to be instantiated.
In fact,
there is absolutely, positively no way to create a
B
instance without creating an
A
instance first.
If I modify class B to add super():
public class B extends A {
public B() {
super();
System.out.println("Hello from B");
}
}
the output would be identical to the first version.
In fact,
the generated Java bytecode would be identical.
When there is no explicit call to
super()
as the first statement in a constructor,
the Java compiler implicitly adds a call to the no-argument
super()
to invoke the no-argument constructor of the parent class.
There is never a need to add an explicit call to a no-argument
super()
.
While the B
object is being instantiated in the call to new B()
,
the Java runtime also called the default no-argument constructor from the
Object
class before calling
A
’s
constructor.
Thus,
the single statement
B myB = new B();
caused three constructors to be run,
and none of the constructors called
super()
for it to happen.
I think a lot of Java developers end up believing you need to call
super()
in order for the superclass’s constructor to be called because so much Java code
out there includes extraneous calls to
super()
.
For instance,
here is a constructor taken verbatim from a
Hello World
J2ME coding example from
Research in Motion Ltd.,
the makers of the BlackBerry smart phones.
//create a new screen that extends MainScreen, which provides
//default standard behavior for BlackBerry applications
final class HelloWorldScreen extends MainScreen
{
public HelloWorldScreen()
{
//invoke the MainScreen constructor
super(); // FROM COMMENT, DEVELOPER BELIEVES super() IS REQUIRED
//add a title to the screen
LabelField title = new LabelField("HelloWorld Sample", LabelField.ELLIPSIS
| LabelField.USE_ALL_WIDTH);
setTitle(title);
//add the text "Hello World!" to the screen
add(new RichTextField("Hello World!"));
}
If I were a developer just learning Java,
I would assume the call to
super()
is required in order to invoke the parent class’s constructor.
Why else would the
HelloWorldScreen
developer code it, and add that comment
to explicitly point out the call to the parent class?
I
searched Krugle
for open source projects using calls to the no-argument
super()
and found 82,347 Java files,
including code from major projects like Eclipse and
GlassFish.
It seems many developers like explicitly invoking
super()
.
I can see one possible reason for doing so. Perhaps there are several constructors in the parent class and the developer wants to call out that he or she is using the no-argument version. The first danger I see with adding extra code that adds no behavior to a program is the risk of adding confusion. For instance, I recently ran across code with constructors that looked something like this:
public class SpecialClass extends RegularClass {
private int x, y;
public SpecialClass() {
super();
}
public SpecialClass(int x) {
super();
this.x = x;
this.y = 0;
}
public SpecialClass(int x, int y) {
this.x = x;
this.y = y;
}
}
The first two constructors explicitly called
super()
,
but the third constructor didn’t.
Was that a mistake?
Did the developer mean to add a call to a different superclass constructor, like
super(x, y)
,
but forgot?
If not,
why did he leave off the third call to super()?
Finding small inconsistencies in code like this waste development
time as the reader tracks down whether the inconsistency was the result
of harmless oversight or the result of an error that is now a bug.
Code that doesn’t do anything,
without a documented reason for being there,
seems way more hazardous to understanding code than any value
I can see that might be gained from “documenting” that you really
meant the automatic behavior to be taken by writing extra code.
Similar to seeing a class that extends
java.lang.Object
,
I end up asking why did the developer do that.
(If you use
super()
regularly for documentation purposes,
I would appreciate hearing your reasons.)
The second danger in adding extraneous calls to
super()
is that it seems to be teaching a lot of new Java developers
that
super()
is required in order for parent constructors to be invoked.
At least that certainly is my recent experience from interviewing
Java developers.
The only time
super
is required is when it takes a non-empty argument list
to invoke a constructor in the parent class that requires parameters.
For example,
here is my base class to represent a
knight from the movie
Monty Python and the Holy Grail.
Note that the constructor requires an argument.
public class EnglishKnight {
private String whatISay;
public EnglishKnight(String saying) {
whatISay = saying;
}
@Override
public String toString() {
return whatISay;
}
}
This following subclass (with an error) is meant to be a certain kind of knight from the movie:
public class KnightWhoSaysNeep extends EnglishKnight {
public KnightWhoSaysNeep() {
// syntax error: parent class has no default constructor
}
}
You probably see the compile-time error.
Since
KnightWhoSaysNeep
extends
EnglishKnight
,
and since
EnglishKnight
does not contain a no-argument constructor,
the
KnightWhoSaysNeep
class must override the implicit (and illegal) call to
super()
in its constructor.
Here’s the error from Eclipse:
Implicit super constructor EnglishKnight() is undefined. Must explicitly invoke another constructor
To fix
KnightWhoSaysNeep
we need to call one of the valid constructors in the superclass.
In this case,
there is only one constructor in the superclass,
which takes a String as an argument.
public class KnightWhoSaysNeep extends EnglishKnight {
public KnightWhoSaysNeep() {
super("Neep!");
}
}
The corrected
KnightWhoSaysNeep
class demonstrates the proper use of
super
—
one that takes a parameter to override default behavior.
It’s nii, not neep…
HEAD KNIGHT: We are the keepers of the sacred words: Ni, Peng, and Neee-wom!
RANDOM: Neee-wom!
ARTHUR: Those who hear them seldom live to tell the tale!
HEAD KNIGHT: The Knights Who Say ‘Ni’ demand a sacrifice!
ARTHUR: Knights of Ni, we are but simple travelers who seek the enchanter who
lives beyond these woods.
HEAD KNIGHT: Ni!
Super!! I can’t resist the idea presented here . Too useful even for old geeks.
(If you use super() regularly for documentation purposes, I would appreciate hearing your reasons.)
I have a reason. All my constructor code has one of two possible first lines (with or without parameters):
Every deviation from this rule would be an error. This is handy in two cases:
With one look at the first lines of every constructor, you get a feeling what type of class your current code is. In a code review situation, this look ensures proper object instantiation in most cases (especially in combination with final members).
I know that the reason isn’t strong and the extra code isn’t necessary. So its a matter of personal taste, with slightly better reasons to the “it’s bloat” attitude.
M,
Thank you for challenging my statement. Section 12.5 of the JLS indeed supports your argument that only one instance is created.
Conceptually, I have looked at object creation as having each superclass also instantiated as a separate object instance, but you have a good point that there is no need for separate object instances. The JLS says instance fields from superclasses become part of the object instance being created with the “new” keyword, which does not make sense if those superclasses were also being instantiated as separate objects.
Conceptually, I wonder if looking at object creation as creating separate instances of the superclasses would lead to a nonsensical state of affairs. Since there is no way for a subclass to return to callers a reference to one of its (conceptual) superclass instances — e.g. you can’t say “return this.super;” — then the garbage collector would always free these conceptual instances when the subclass instance is freed. Can you think of an example when this conceptual world of separate object instances for superclasses would lead to a violation of the JLS?
Again, thank you for posting your comment. I stand corrected about superclass object creation unless someone with expert knowledge of the Java runtime offers a better explanation.
-Tom
Hi Tom,
Actually, i think the JLS is kinda vague (guess it should be…lol) so its up to the VM for interpretation and implementation.
BTW, Thanks for the great post.
Mike
Hi..i don’t think there are 2 objects created when instantiating a subclass. An instance of the superclass will not be created. Please correct me if i’m wrong.
An object is constructed like an onion, layer by layer and inner layers first. The implicitly created ‘super()’ call ensures that. There is one exception to the rule (which makes it an illegal construct): if all constructors of a class have a first line ‘this( … )’ no call to a superclass’ constructor is made and it is flagged as an error by the compiler.
kind regards,
Jos