7.6 The super Keyword and super()
When a child class inherits from a parent, it can use the parent's member fields and methods. However, sometimes the child and parent have identically named members that conflict, or after overriding a parent method you still need to call the original parent implementation. This is when the super keyword is used.
1. The Reference Variable super
super is a reference variable used inside a child class to access parent class members. Just as this points to "myself," super points to "the parent who created me."
Resolving Name Conflicts with Parent Fields
When a child class has a field with the same name as a parent field, super distinguishes between them.
class Parent {
int x = 10;
}
class Child extends Parent {
int x = 20;
void method() {
System.out.println("x=" + x); // child's closest variable (20)
System.out.println("this.x=" + this.x); // child's own instance field (20)
System.out.println("super.x=" + super.x); // parent's inherited field (10)
}
}
Calling the Original Parent Method
After a child overrides a parent method, super lets you reuse the parent's original logic without duplication.
class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
String getLocation() {
return "x: " + x + ", y: " + y;
}
}
class Point3D extends Point {
int z;
Point3D(int x, int y, int z) {
super(x, y);
this.z = z;
}
@Override
String getLocation() {
// Reuse parent logic and append child-specific data
return super.getLocation() + ", z: " + z;
}
}
public class Point3DTest {
public static void main(String[] args) {
Point3D p = new Point3D(1, 2, 3);
System.out.println(p.getLocation()); // x: 1, y: 2, z: 3
}
}
2. Parent Constructor Invocation — super()
When creating an instance of a child class, the parent portion must be allocated and initialized first so the child can fully use the inherited properties. Java provides the super() call to ensure this.
- Rule: The very first line of every child constructor must call either another constructor of the same class (
this()) or the parent constructor (super()). - Automatic insertion: If you omit this, the compiler automatically inserts an empty
super();on the first line.
class Point {
int x, y;
// Parent has only a parameterized constructor — no default constructor!
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Point3D extends Point {
int z;
Point3D() {
// The compiler tries to insert super() here,
// but Parent has no default constructor → COMPILE ERROR!
} // compile error example
Point3D(int x, int y, int z) {
super(x, y); // explicitly call the parent's parameterized constructor
this.z = z; // then initialize child's own field
}
}
3. Practical Example: Employee Hierarchy
// Base class
public class Employee {
protected String name;
protected String department;
protected double baseSalary;
public Employee(String name, String department, double baseSalary) {
this.name = name;
this.department = department;
this.baseSalary = baseSalary;
}
public double calculateSalary() {
return baseSalary;
}
public void introduce() {
System.out.printf("Name: %s | Dept: %s | Base: $%.2f%n",
name, department, baseSalary);
}
@Override
public String toString() {
return String.format("%s (%s) - $%.2f", name, department, calculateSalary());
}
}
// Manager adds a bonus
public class Manager extends Employee {
private double bonus;
private int teamSize;
public Manager(String name, String department, double baseSalary,
double bonus, int teamSize) {
super(name, department, baseSalary); // call parent constructor first
this.bonus = bonus;
this.teamSize = teamSize;
}
@Override
public double calculateSalary() {
return super.calculateSalary() + bonus; // reuse parent logic
}
@Override
public void introduce() {
super.introduce(); // reuse parent's introduction
System.out.printf(" Role: Manager | Team: %d | Bonus: $%.2f%n",
teamSize, bonus);
}
}
// SeniorManager adds extra compensation
public class SeniorManager extends Manager {
private double stockOptions;
public SeniorManager(String name, String department, double baseSalary,
double bonus, int teamSize, double stockOptions) {
super(name, department, baseSalary, bonus, teamSize); // chain to Manager
this.stockOptions = stockOptions;
}
@Override
public double calculateSalary() {
return super.calculateSalary() + stockOptions; // Manager salary + stock
}
@Override
public void introduce() {
super.introduce(); // Manager's introduce (which calls Employee's)
System.out.printf(" Stock Options: $%.2f%n", stockOptions);
}
}
// Test
public class EmployeeTest {
public static void main(String[] args) {
Employee emp = new Employee("Alice", "Engineering", 5000);
Manager mgr = new Manager("Bob", "Engineering", 7000, 1500, 8);
SeniorManager sr = new SeniorManager("Carol", "Engineering", 9000, 2500, 20, 3000);
Employee[] staff = { emp, mgr, sr };
System.out.println("=== Staff Report ===");
for (Employee e : staff) {
e.introduce();
System.out.printf(" Total salary: $%.2f%n%n", e.calculateSalary());
}
System.out.println("=== Salary Summary ===");
for (Employee e : staff) {
System.out.println(e);
}
}
}
Output:
=== Staff Report ===
Name: Alice | Dept: Engineering | Base: $5000.00
Total salary: $5000.00
Name: Bob | Dept: Engineering | Base: $7000.00
Role: Manager | Team: 8 | Bonus: $1500.00
Total salary: $8500.00
Name: Carol | Dept: Engineering | Base: $9000.00
Role: Manager | Team: 20 | Bonus: $2500.00
Stock Options: $3000.00
Total salary: $14500.00
=== Salary Summary ===
Alice (Engineering) - $5000.00
Bob (Engineering) - $8500.00
Carol (Engineering) - $14500.00
4. The Object Class Methods
Every class ultimately inherits from java.lang.Object. Understanding its key methods helps you understand super at the root level.
public class ObjectMethodsDemo {
private int id;
private String name;
public ObjectMethodsDemo(int id, String name) {
this.id = id;
this.name = name;
}
// Override Object.toString()
@Override
public String toString() {
return "ObjectMethodsDemo{id=" + id + ", name='" + name + "'}";
}
// Override Object.equals()
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // same reference
if (!(obj instanceof ObjectMethodsDemo other)) return false;
return this.id == other.id && this.name.equals(other.name);
}
// Override Object.hashCode() — must be consistent with equals()
@Override
public int hashCode() {
return java.util.Objects.hash(id, name);
}
public static void main(String[] args) {
ObjectMethodsDemo a = new ObjectMethodsDemo(1, "Alice");
ObjectMethodsDemo b = new ObjectMethodsDemo(1, "Alice");
ObjectMethodsDemo c = new ObjectMethodsDemo(2, "Bob");
System.out.println(a.toString()); // ObjectMethodsDemo{id=1, name='Alice'}
System.out.println(a.equals(b)); // true (same content)
System.out.println(a.equals(c)); // false
System.out.println(a.hashCode() == b.hashCode()); // true
// Object.getClass() — runtime type information
System.out.println(a.getClass().getSimpleName()); // ObjectMethodsDemo
// Call super's version (Object's default)
// super.toString() would give something like "ObjectMethodsDemo@1b6d3586"
}
}
5. Constructor Chaining with super() and this()
public class Product {
private String name;
private double price;
private String category;
private int stock;
// Most specific constructor
public Product(String name, double price, String category, int stock) {
this.name = name;
this.price = price;
this.category = category;
this.stock = stock;
}
// Delegate to the main constructor via this()
public Product(String name, double price) {
this(name, price, "General", 0); // this() must be on first line
}
public Product(String name, double price, String category) {
this(name, price, category, 0);
}
@Override
public String toString() {
return String.format("Product{name='%s', price=%.2f, category='%s', stock=%d}",
name, price, category, stock);
}
}
public class ChildProduct extends Product {
private String brand;
public ChildProduct(String name, double price, String category, int stock, String brand) {
super(name, price, category, stock); // call parent constructor
this.brand = brand;
}
@Override
public String toString() {
return super.toString() + ", brand='" + brand + "'";
}
}
Summary
| Keyword | Role |
|---|---|
super | Reference to the parent inside a child class. Used to access parent fields/methods that are hidden by overriding. |
super() | Call the parent's constructor. Must appear on the very first line of the child constructor. |
this() | Call another constructor in the same class. Also must be on the first line. |
super.method() is a common pattern in frameworks. Spring's AbstractController or JPA's base entity classes often define lifecycle hooks that child classes extend by calling super.methodName() first, then adding their own logic. Understanding super is essential for working with inheritance-heavy frameworks.