Preface
One problem I notice among new Java programmers is the confusion about when and where to use the super
keyword. Why do things occasionally work when I don't call it? Why do I get compilation errors in other cases for not calling it? Hopefully things will start to make sense by the end of this.
Much of this is based on the Java Tutorial.
Constructors
Let's start with constructors. Remember that every class you create in Java is a subclass of Object
. The Object
class has a default no-argument constructor that looks like Object()
.
If you make a subclass, each constructor in the subclass must call super
to a constructor in the parent class. Here's the gotcha, if you don't explicitly call super
in the subclass constructor, the compiler will try to automatically prepend a super();
call for you. Pay special attention to that last part. For some this may be a strange concept, but code generation is prevalent throughout Java.
Many people don't realize that calling super
is required for subclass constructors because the compiler has secretly been doing it for them. You wouldn't notice anything if your subclass only has a default constructor. If your subclass has multiple constructors, sometimes you can get lucky that calling super()
is harmless to your code.
The problem becomes apparent when you have a parent class with no default constructor. If you try to subclass and don't provide a super
call for each constructor, then it will complain that super()
doesn't exist, rightfully so because it doesn't in the parent class. You may think to yourself that it's odd the compiler is complaining about something not even in your code! You are now equipped to throw away that thought and thank the compiler for performing admirably.
One thing to note is that constructors do not have to make a super
call to a matching constructor in the parent class. You can mix and match however you please, and sometimes it's required of you. I'll show you an example of this.
Constructor Example
Check out some different examples of what I'm talking about:
public class ConstructorExample {
public ConstructorExample() {
//super() added by compiler to Object()
}
public ConstructorExample(int value) {
//super() added by compiler to Object()
}
public static class SubclassA extends ConstructorExample {
public SubclassA() {
//super() added by compiler to ConstructorExample()
}
public SubclassA(int value) {
//super() added by compiler to ConstructorExample()
}
}
}
public class ConstructorExample2 {
public ConstructorExample2(int value) {
//super() added by compiler to Object()
}
public static class SubclassB extends ConstructorExample2 {
public SubclassB(int value) {
//uh-oh, won't compile. it's complaining
//that ConstructorExample2() doesn't exist
//when it inserts super()
}
}
}
Methods
Contrary to constructors, it is not required by Java to call super
in overridden methods. Calling a super
method is no different than calling normal methods, just treat super
as the object you are calling the method on. Assuming the parent class has the method someMethod()
you can call it like: super.someMethod()
. You can capture values like normal too: int someValue = super.someMethod();
While it is not a language requirement, some frameworks need you to call super
in order to work correctly. As always, read the documentation of whatever you are trying to work with! Android is one such framework. Those familiar with Android programming may remember calls such as super.onResume()
to make their app work.
Types of Method Overrides
I consider there to be two types of method method overriding: replacement and extension. I'll start with replacement overriding since most will be familiar with that.
Replacement overriding means that you are replacing the parent method's implementation with your own. This is just your basic method override with no call to super
. The compiler will use the method in the child class and not bother with the parent class.
Extension is an interesting use of overrides. The name gives it away, but you can "extend" the behavior of the parent method by calling it in the child method using super
. For example, you could choose to append or prepend some text to a String that the parent method returns. Or, you could choose to perform another action that has nothing to do with the return value. Taking advantage of method extensions can lead to some cleaner polymorphic code.
Method Overriding Examples
public class MethodExample {
public String someString() {
return "some String";
}
public static class SubclassA extends MethodExample {
@Override
public String someString() {
return "another string"; //replaces the parent implementation
}
}
}
public class MethodExample2 {
public String someString() {
return "some String";
}
public static class SubclassB extends MethodExample2 {
@Override
public String someString() {
return "prepend: " + super.someString(); //extends the parent implementation
}
}
}
Wrapping Up
This is just scratching the surface of what you can do, but hopefully it covered the basics. There's more to method overriding than just this so I tried to keep it all related to the super
keyword.
As always, design your application in the most sensible and maintainable approach. Put yourself in the shoes of a new engineer, or even future you, trying to read your code. For example, mixing and matching super
calls for constructors can be confusing unless you explain why you are doing so.