Java Keyword: super
As a reminder, inheritance is one of the core principles of Object Orientated Programming, along with encapsulation, abstraction and polymorphism. Inheritance allows one class to inherit attributes and behaviours from another class. To enable this, the keyword extends is used by the class that is inheriting from another class. This relationship is organised into two categories:
- subclass (child) – the class that inherits from another class
- superclass (parent) – the class being inherited from
The super keyword is used in a child class (or subclass) to refer to parts of the parent class (or superclass).
For example, a college has a superclass of Student and a subclass of Programmer, and possibly a ton of other student types like Accountants, Artists, etc. As expected, the Student class will have all the common attributes and behaviours that all students have and the Programmer class will have programmer specific attributes and behaviours.
This is what the Student class might looking like:
public class Student { String name; int grade; public Student(){} public void nickName() { System.out.println("Newbie!"); } public void deptName(){ System.out.println("Working it out!"); } }
There are a couple of class variables for the student name and grade, a no-argument constructor, and a couple of methods that output a nickname (“Newbie!”) and a department name (“Working it out!”). This is the super class, this is the class that will be extended.
The Programmer class might look like this:
public class Programmer extends Student { String favCodeLang; @Override public void nickName() { System.out.println("Codesters!"); } }
First thing to note is the extends keyword on line 1 which means this class (Programmer) is inheriting the class Student which includes the method nickName. This is important as the Programmer class also has a nickName method (line 5 to 7) that will output the programmer’s nickname of “Codesters!”. Essentially, the Programmer version of the nickName method is overriding the Student version of the nickName method. Note the @override annotation on line 4: this is not required but is advised when overriding methods.
To see this working, a new Programmer object needs to be created within the main method of the project’s main class (in this case the SuperStudent class) and the nickName method called:
public class SuperStudent { public static void main(String[] args) { Programmer myProgrammer = new Programmer(); myProgrammer.nickName(); } }
When this program is run, the output will be the Programmer implementation of the nickName method:
run: Codesters! BUILD SUCCESSFUL (total time: 0 seconds)
Before moving on, be very sure you understand why the Programmer implementation of the nickName method was called and not the Student implementation.
- The Student class is the superclass, and contains a nickName method
- The Programmer class is the subclass and extends the Student class but also has its own nickName method
- This extension process informs Java that it should use the subclass (Programmer) version of the nickName method rather that the superclass (Student) version.
- It’s the logical choice for Java. After all, why is it in the Programmer class if the coder didn’t want to use it for the programmer students?
Using the super keyword
What if the program required the Student implementation of the nickName method (that returns “Newbie!”) rather than the Programmer implementation (that returns “Codesters!”) as seen above? That method is in the superclass of the Programmer class (the Student class), and this is where the super keyword is useful.
By calling the nickName method using the super keyword, the superclass (Student) implementation of the nickName method is called.
Let’s try this by adding a call to the superclass nickName method using dot notation (super.nickName();) within the Programmer class version of the nickName method:
public class Programmer extends Student { String favCodeLang; @Override public void nickName() { super.nickName(); System.out.println("Codesters!"); } }
The output includes both the superclass (line 6) and subclass (line 7) implementations of the nickName method:
run: Newbie! Codesters! BUILD SUCCESSFUL (total time: 0 seconds)
Using super in other methods
Calling the superclass implementation of a method does not require that call statement to be inside the subclass implementation of the method, it can be in any non-static method within the subclass. For example, if we add another (non-static) method to the Programmer subclass called javaCoders, we can call the superclass nickName method from there as well:
public class Programmer extends Student { String favCodeLang; @Override public void nickName() { super.nickName(); System.out.println("Codesters!"); } public void javaCoders() { super.nickName(); } }
Since using the super keyword is really only useful when overriding methods, there’s not much use in the above example BUT it’s good to know that it’s possible.
Using super without overriding
It’s also good to know that a superclass method can be called from a subclass even if it is not overridden in the subclass. For example, we have a method in the superclass Student called deptName. This method outputs the string “Working it out!”, here it is:
public class Student { String name; int grade; public Student(){} public void nickName() { System.out.println("Newbie!"); } public void deptName(){ System.out.println("Working it out!"); } }
Even though the subclass does not override this method, we can still call this method (line 9 below) using the super keyword from the subclass Programmer:
public class Programmer extends Student { String favCodeLang; @Override public void nickName() { super.nickName(); System.out.println("Codesters!"); super.deptName(); } public void javaCoders() { super.nickName(); } }
Since we are not overriding the deptName method, Java is clever enough to know that it needs to call the superclass deptName method since it is already available to it via inheritance so actually the super keyword is not necessary but it’s worth knowing that you can use it if you want to.
You cannot use the super keyword to access private methods in the superclass. Remember, a method that has a private access modifier can only be accessed from the same class. A method that has a public or protected access modifier will be accessible using the super keyword.
Using super with parent class constructors
You can use the super keyword to call the parent class’s constructors. The Student class (the parent class) already has a no-args constructor (called Student as you would expect). Let’s say we want to have another constructor that does have arguments – this is constructor overloading and is very common. Let’s use the class variables name and grade as the arguments:
public class Student { String name; int grade; //no-args constructor public Student(){} //overriding constructor with arguments public Student(String name, int grade){ this.name = name; this.grade = grade; } }
Returning to the Programmer class, we can see that we have a class variable favCodeLang that is unique to the programmer class (their favourite programming language) and no constructor for Programmer objects (we haven’t needed one so far).
Let’s create a constructor for Programmer objects that require a name, grade and faveCodeLang:
public class Programmer extends Student { String favCodeLang; //new constructor: public Programmer(String name, int grade, String favCodeLang){ this.name = name; this.grade = grade; this.favCodeLang = favCodeLang; } //exisiting code: @Override public void nickName() { super.nickName(); System.out.println("Codesters!"); super.deptName(); } public void javaCoders() { super.nickName(); } }
Lines 5-9 above contain the new Programmer constructor. Within the constructor, the this keyword is used to assign the constructor’s arguments to the Programmer variable favCodeLang and the variables name and grade inherited from the Student class.
Let’s think for a minute:
- The Student class already has a constructor that is doing part of what the Programmer constructor is doing:
- namely dealing with the variables name and grade (lines 11 and 12 in the Student class code above).
- Wouldn’t it be great if we could used that Student constructor rather than repeating the same code in the Programmer constructor?
We can by using the super keyword to call it and provide the required arguments (name and grade):
public class Programmer extends Student { String favCodeLang; //new constructor: public Programmer(String name, int grade, String favCodeLang){ //calling the parent class constructor that has matching argumeents: super(name, grade); this.favCodeLang = favCodeLang; } //exisiting code: @Override public void nickName() { super.nickName(); System.out.println("Codesters!"); super.deptName(); } public void javaCoders() { super.nickName(); } }
Have a look at Line 7 above:
super(name, grade);
This will call the constructor within the parent class whose arguments match those provided. In the Student class there is a Student constructor that matches that criteria and this constructor will be called.
All that remains is to correctly create a Programmer object that includes the arguments required (name, grade and favCodeLang):
public class SuperStudent { public static void main(String[] args) { //Updated object with the required arguments: Programmer myProgrammer = new Programmer("Andrew", 100, "JAVA"); myProgrammer.nickName(); } }
From line 5 above, we can see that the programming student is Andrew, with a 100 grade and a favourite programming language of JAVA…. of course!
Some things to watch out for:
Using the super keyword to call a parent constructor must be done on the very first line within the child constructor – and nowhere else!
Also, if we leave out the super constructor call:
super(name, grade);
Java will automatically call the no-args constructor instead:
super( );
As long as there is a no-args constructor in the parent class all will be well. However, is there is not, you will get an error!