In this post, we’ll dive deep into the super
keyword and explore how it works in different scenarios. The first part covers using super
to access parent class methods and variables, while the second part explains constructor chaining, including all nuances involved.
1. Using super
to Access Parent Class Methods and Variables
The super
keyword allows child classes to reuse functionality from the parent class, including methods and variables. It’s particularly useful when you want to:
- Call the parent class’s overridden methods.
- Access hidden variables when a child class has the same variable name as the parent class.
Example Code:
Parent Class
package super_keyword;
class EmployeeParent {
private int id, depId;
protected String name;
private double basicSal;
public EmployeeParent(int id, String name, int depId, double basicSal) {
this.id = id;
this.name = name;
this.depId = depId;
this.basicSal = basicSal;
}
// Parent method to compute net salary
protected double computeNetSalary() {
return basicSal;
}
@Override
public String toString() {
return "EmployeeParent [id=" + id + ", depId=" + depId + ",
name=" + name + ", basicSal=" + basicSal + "]";
}
}
Child Class
class ManagerChild extends EmployeeParent {
private double perfBonus;
public ManagerChild(int id, String name, int depId, double basicSal,
double perfBonus) {
super(id, name, depId, basicSal); // Calling Parent Constructor
this.perfBonus = perfBonus;
}
// Overriding Parent Method
@Override
public double computeNetSalary() {
// Using super to call parent class method
/* Without using super keyword here, compiler assumes that we are
using recursion and ends up with exception StackOverflowError. */
return perfBonus + super.computeNetSalary();
}
@Override
public String toString() {
// Using super to reuse parent’s toString()
return "ManagerChild [perfBonus=" + perfBonus + ", " +
super.toString() + "]";
}
public void displayParentName() {
// Accessing parent’s variable
System.out.println("Employee's Name: " + super.name);
}
public static void main(String[] args) {
ManagerChild manager = new ManagerChild(1, "Arshi", 2, 10000, 1890);
System.out.println(manager);
System.out.println("Net Salary: " + manager.computeNetSalary());
manager.displayParentSalary();
}
}
Explanation:
-
Accessing Parent Method Using
super
:- In
computeNetSalary()
,super.computeNetSalary()
invokes the parent class’s version of the method. - In Child's
toString()
,super.toString()
invokes parent class’s version of the method.
- In
Accessing Parent Variable Using
super
:
ThedisplayParentName()
method demonstrates how to access a parent class’s variable (name
) usingsuper
.Calling Parent’s Constructor with
super()
:
We usesuper(id, name, ...)
to initialize common fields by invoking the parent class constructor.
2. Constructor Chaining with super()
Constructor chaining is a powerful feature in Java that allows a subclass constructor to invoke a parent class constructor, ensuring that the parent class is properly initialized before executing the child class's constructor.
The super()
keyword plays a crucial role in this process. Let's explore the nuances of constructor chaining and how it operates.
Key Concepts of Constructor Chaining:
1. There will always be a call to ANY Parent Constructor from ALL Child Constructors:
In Java, every child class constructor has to call a constructor from its parent class. This is crucial for establishing the proper initialization sequence in a class hierarchy.
Example:
package constructor_chaining;
public class ConstructorChainingParent {
// Parent Default Constructor
public ConstructorChainingParent() {
System.out.println("Parent DEFAULT Constructor Called");
}
// Parent constructor with one parameter
public ConstructorChainingParent(String name) {
System.out.println("Parent PARAMETERIZED Constructor Called
with name: " + name);
}
// Parent constructor with two parameters
public ConstructorChainingParent(String name, int id) {
System.out.println("Parent PARAMETERIZED Constructor Called
with name: " + name + " and id: " + id);
}
}
public class ConstructorChainingChild extends ConstructorChainingParent {
// Child Default Constructor
public ConstructorChainingChild() {
// Compiler inserts super() automatically
System.out.println("Child DEFAULT Constructor Called");
}
// Child constructor with one parameter
public ConstructorChainingChild(String name) {
super(name); // Calling parent constructor with one parameter
System.out.println("Child PARAMETERIZED Constructor Called
with name: " + name);
}
// Child constructor with two parameters
public ConstructorChainingChild(String name, int id) {
// Calling parent constructor with two parameters
super(name, id);
System.out.println("Child PARAMETERIZED Constructor Called
with name: " + name + " and id: " + id);
}
public static void main(String[] args) {
// Creating an instance of the child class
ConstructorChainingChild child = new ConstructorChainingChild();
// Output:
// Parent DEFAULT Constructor Called
// Child DEFAULT Constructor Called
// Creating an instance of the child class with one parameter
ConstructorChainingChild child1 = new ConstructorChainingChild("Alice");
// Output:
// Parent PARAMETERIZED Constructor Called with name: Alice
// Child PARAMETERIZED Constructor Called with name: Alice
// Creating an instance of the child class with two parameters
ConstructorChainingChild child2 = new ConstructorChainingChild("Bob", 1);
// Output:
// Parent PARAMETERIZED Constructor Called with name: Bob and id: 1
// Child PARAMETERIZED Constructor Called with name: Bob and id: 1
}
}
Explanation
-
Explicit Calls to Parent Constructors:
- In this example, both parameterized constructors in the
ConstructorChainingParent
class are called explicitly by the constructors of theConstructorChainingChild
class. - This demonstrates that invoking a parent constructor is mandatory in child constructors.
- In this example, both parameterized constructors in the
-
Implicit Call to Default Constructor:
- Since there was no explicit call to the
ConstructorChainingParent
class's default constructor, it may appear that the rule is being broken. - However, this is acceptable because the compiler automatically inserts a call to the parent class' default constructor using
super()
. - This implicit behavior occurs when a child class constructor does not explicitly call any parent class constructor.
- Since there was no explicit call to the
2. If there are NO parent constructors, the compiler implicitly inserts a default constructor. This default constructor gets called from child class constructors implicitly.
In Java, when there are NO constructors defined in a class, the compiler automatically provides an implicit default constructor that initializes instance variables to their default values. This default constructor is called behind the scenes when a child class constructor is invoked without an explicit call to a parent constructor using super()
.
Example:
package constructor_chaining;
public class ConstructorChainingParent {
// No constructor defined
// The compiler provides an implicit default constructor.
}
public class ConstructorChainingChild extends ConstructorChainingParent {
public ConstructorChainingChild() {
// Compiler inserts super() behind the scenes
// Calls the compiler-provided parent class's default constructor
System.out.println("Child DEFAULT Constructor Called");
}
public static void main(String[] args) {
// Creating an instance of the child class
ConstructorChainingChild child = new ConstructorChainingChild();
// Output:
// Child DEFAULT Constructor Called
}
}
In this example, since there are NO constructors defined in the ConstructorChainingParent
, the compiler automatically provides a default constructor. When the ConstructorChainingChild
is instantiated, it implicitly calls this default constructor, ensuring that the parent class is properly initialized, even though we don't see the super()
call in the child's constructor.
3. If parent class only has parameterized constructors, compiler DOESN'T provide a default constructor. Thus, Calling Parent Parameterized Constructor from ALL child constructors becomes mandatory.
In cases where the parent class does not provide a default constructor and has only parameterized constructors, the compiler does not automatically insert a default constructor.
Consequently, all child class constructors must explicitly call one of the parent class's parameterized constructors as there is NO default constructor.
Example:
package constructor_chaining;
public class ConstructorChainingParent {
// Parent Parameterized Constructor
public ConstructorChainingParent(String name) {
System.out.println("Parent PARAMETERIZED Constructor Called with
name: " + name);
}
}
public class ConstructorChainingChild extends ConstructorChainingParent {
// Child Default Constructor
public ConstructorChainingChild() {
/* Must call parent parameterized constructor,
* Otherwise, Compile Error occurs
* Error: ConstructorChainingParent requires a String parameter
*/
super("Default Name");
System.out.println("Child DEFAULT Constructor Called");
}
// Child Parameterized Constructor
public ConstructorChainingChild(String name) {
// Calling parent constructor from ALL child constructors
super(name);
System.out.println("Child PARAMETERIZED Constructor Called with
name: " + name);
}
public static void main(String[] args) {
// Creating an instance of the child class
ConstructorChainingChild childDefault = new ConstructorChainingChild();
// Output:
// Parent PARAMETERIZED Constructor Called with name: Default Name
// Child DEFAULT Constructor Called
// Creating an instance of the child class with the parameterized constructor
ConstructorChainingChild childParam = new ConstructorChainingChild("Alice");
// Output:
// Parent PARAMETERIZED Constructor Called with name: Alice
// Child PARAMETERIZED Constructor Called with name: Alice
}
}
Explanation:
Parameterized Constructor in Parent Class:
TheConstructorChainingParent
class only provides a parameterized constructor with aString
parameter.-
Compiler Does Not Provide a Default Constructor:
- Since a parameterized constructor is explicitly defined, the compiler does not provide an implicit default constructor.
- This means that if a child class does not explicitly call any parent constructor, the compiler cannot insert
super()
to call a non-existent default constructor, leading to a compile-time error.
Mandatory Call to Parameterized Constructor:
All child class constructors must explicitly call one of the parent’s parameterized constructors usingsuper()
to avoid a compile-time error.-
Demonstration in Example Code:
- The default constructor in
ConstructorChainingChild
calls the parent’s parameterized constructor with"Default Name"
. - The parameterized constructor in
ConstructorChainingChild
also calls the parent constructor with the providedname
parameter.
- The default constructor in
This ensures that the child class properly initializes the parent class's state with the required data.
3. Using this()
and super()
in Constructors
If you are new to this
keyword, I recommend checkout out Mastering THIS Keyword in Java: A Key to Clean and Effective Code first to better understand this section.
Both this()
and super()
are special calls used to invoke constructors, but they follow specific rules that impact their usage:
-
this()
andsuper()
Must Be the First Statement in a Constructor:- When using
this()
to call another constructor within the same class orsuper()
to invoke a parent class constructor, the call must always be the first statement in the constructor body.
- When using
-
this()
andsuper()
Cannot Be Used Together in the Same Constructor:- Since only one of them can occupy the first statement position, it is impossible to call both
this()
andsuper()
within the same constructor. - This restriction ensures the proper initialization sequence is maintained either within the same class hierarchy (
this()
) or across parent-child classes (super()
).
- Since only one of them can occupy the first statement position, it is impossible to call both
These rules highlight how Java enforces constructor chaining in a structured manner to ensure consistent initialization at every level.
Key Takeaways
-
Accessing Parent Class Methods and Variables:
- The
super
keyword allows a child class to reuse the parent class’s methods and variables. - It is useful for calling overridden methods and accessing hidden variables from the parent class.
- The
-
Constructor Chaining with
super()
:- Every child class constructor must invoke a parent class constructor, ensuring that parent class initialization occurs before the child’s logic executes.
- If the parent class defines only parameterized constructors, child class constructors must explicitly call one of them, as the compiler won’t insert a default constructor.
-
this()
vssuper()
in Constructors:- Both
this()
andsuper()
must be the first statement in a constructor. - They cannot coexist in the same constructor, enforcing structured constructor chaining within and across class hierarchies.
- Both
Conclusion
Understanding how to use super
effectively enhances your ability to write clean, well-structured, and maintainable Java code, especially in complex inheritance scenarios. Mastery of these concepts is also crucial for interviews, as it demonstrates your grasp of key object-oriented principles.
Stay tuned for forthcoming posts in this series, where we’ll explore other keywords and delve into their nuances.🚀
Related Posts
Happy Coding!