Java super Keyword
Java super Keyword
The super keyword in Java is a reference to the parent class portion of the current object. It gives a child class access to three things it would otherwise be cut off from: the parent's constructor, the parent's overridden methods, and the parent's fields that are shadowed by child fields.
super only makes sense in an inheritance context — it is the counterpart to this for the parent layer. While this points to the current object, super points upward to the parent class definition within that same object. Both references exist for the same object in memory; they just give access to different layers of it.
What Is the super Keyword in Java?
The super keyword is a reference that gives a subclass explicit access to members defined in its immediate parent class. It has three distinct uses:
- ›
super()— calls a parent class constructor from within a child constructor - ›
super.method()— calls a parent class method that has been overridden in the child - ›
super.field— accesses a parent class field that is shadowed by a child field of the same name
All three uses are only valid inside non-static methods or constructors of a subclass. super cannot be used in static methods — static context has no object instance, so there is no parent layer to reference.
Three Uses of the super Keyword
| Use | Syntax | Purpose | Where Valid |
|---|---|---|---|
| Constructor call | super() or super(args) | Calls parent constructor to initialise parent fields | First statement in child constructor only |
| Method call | super.methodName() | Calls parent's overridden version of a method | Any instance method in child class |
| Field access | super.fieldName | Accesses parent field when child has a field of the same name | Any instance method or constructor in child |
Use 1 — super() — Calling the Parent Constructor
super() must be the first statement in a child constructor. It calls the parent class constructor to initialise the fields that belong to the parent. If you do not write super() explicitly, the Java compiler inserts a no-argument super() automatically — but only if the parent has a no-arg constructor. If the parent has only parameterised constructors, you must call the correct one explicitly.
// File: Vehicle.java
public class Vehicle {
private final String registrationNumber;
private final String brand;
private final int yearOfManufacture;
public Vehicle(String registrationNumber, String brand, int yearOfManufacture) {
this.registrationNumber = registrationNumber;
this.brand = brand;
this.yearOfManufacture = yearOfManufacture;
}
public String getRegistrationNumber() { return registrationNumber; }
public String getBrand() { return brand; }
public int getYearOfManufacture() { return yearOfManufacture; }
public String getBasicInfo() {
return brand + " (" + yearOfManufacture + ") — Reg: " + registrationNumber;
}
}// File: Truck.java
public class Truck extends Vehicle {
private final double payloadCapacityTons;
private final int axleCount;
public Truck(String registrationNumber, String brand,
int yearOfManufacture, double payloadCapacityTons, int axleCount) {
// super() must be first — initialises Vehicle's three final fields
super(registrationNumber, brand, yearOfManufacture);
this.payloadCapacityTons = payloadCapacityTons;
this.axleCount = axleCount;
}
public double getPayloadCapacityTons() { return payloadCapacityTons; }
public int getAxleCount() { return axleCount; }
public String getTruckInfo() {
// super.getBasicInfo() accesses the parent method
return super.getBasicInfo()
+ " | Payload: " + payloadCapacityTons + "T"
+ " | Axles: " + axleCount;
}
}// File: SuperConstructorDemo.java
public class SuperConstructorDemo {
public static void main(String[] args) {
Truck truck = new Truck("MH04CD5678", "Tata Prima", 2022, 35.0, 6);
System.out.println(truck.getTruckInfo());
System.out.println("Brand: " + truck.getBrand()); // inherited from Vehicle
System.out.println("Year : " + truck.getYearOfManufacture()); // inherited
}
}Output:
Tata Prima (2022) — Reg: MH04CD5678 | Payload: 35.0T | Axles: 6
Brand: Tata Prima
Year : 2022
Without super(registrationNumber, brand, yearOfManufacture), the three final fields in Vehicle would never be set. registrationNumber, brand, and yearOfManufacture are private to Vehicle — the Truck constructor cannot set them directly. The only way to initialise them is through the parent constructor, which super() calls.
Use 2 — super.method() — Calling the Parent's Overridden Method
When a child class overrides a parent method, calling the method by name inside the child uses the child's version. super.method() is the only way to explicitly call the parent's version from within the child.
// File: Account.java
public class Account {
private final String accountId;
private double balance;
public Account(String accountId, double initialDeposit) {
this.accountId = accountId;
this.balance = Math.max(0, initialDeposit);
}
public String getAccountId() { return accountId; }
public double getBalance() { return balance; }
public boolean deposit(double amount) {
if (amount <= 0) return false;
balance += amount;
return true;
}
public boolean withdraw(double amount) {
if (amount <= 0 || amount > balance) return false;
balance -= amount;
return true;
}
public String getStatement() {
return "Account: " + accountId + " | Balance: Rs." + balance;
}
}// File: SavingsAccount.java
public class SavingsAccount extends Account {
private final double minimumBalance;
private double interestRate;
public SavingsAccount(String accountId, double initialDeposit,
double minimumBalance, double interestRate) {
super(accountId, initialDeposit);
this.minimumBalance = minimumBalance;
this.interestRate = interestRate;
}
public double getMinimumBalance() { return minimumBalance; }
public double getInterestRate() { return interestRate; }
@Override
public boolean withdraw(double amount) {
// Check minimum balance rule BEFORE delegating to parent
double balanceAfterWithdrawal = getBalance() - amount;
if (balanceAfterWithdrawal < minimumBalance) {
System.out.println("Withdrawal rejected: balance would fall below"
+ " minimum Rs." + minimumBalance);
return false;
}
// Delegate to parent's withdraw() for the actual deduction
return super.withdraw(amount);
}
public void applyMonthlyInterest() {
double interest = getBalance() * (interestRate / 100.0);
super.deposit(interest); // uses parent deposit directly — no need to override
System.out.println("Interest Rs." + String.format("%.2f", interest)
+ " credited to " + getAccountId());
}
@Override
public String getStatement() {
// Extends parent's statement with savings-specific info
return super.getStatement()
+ " | Min Balance: Rs." + minimumBalance
+ " | Interest: " + interestRate + "%";
}
}// File: SuperMethodDemo.java
public class SuperMethodDemo {
public static void main(String[] args) {
SavingsAccount savings = new SavingsAccount("SAV-001", 10000.0, 2000.0, 4.5);
System.out.println(savings.getStatement());
// Valid withdrawal — stays above minimum
System.out.println("\nWithdrawing Rs.5000: " + savings.withdraw(5000.0));
System.out.println(savings.getStatement());
// Rejected — would fall below minimum balance
System.out.println("\nWithdrawing Rs.4000: " + savings.withdraw(4000.0));
// Monthly interest applied
System.out.println();
savings.applyMonthlyInterest();
System.out.println(savings.getStatement());
}
}Output:
Account: SAV-001 | Balance: Rs.10000.0 | Min Balance: Rs.2000.0 | Interest: 4.5%
Withdrawing Rs.5000: true
Account: SAV-001 | Balance: Rs.5000.0 | Min Balance: Rs.2000.0 | Interest: 4.5%
Withdrawing Rs.4000:
Withdrawal rejected: balance would fall below minimum Rs.2000.0
Interest Rs.225.00 credited to SAV-001
Account: SAV-001 | Balance: Rs.5225.0 | Min Balance: Rs.2000.0 | Interest: 4.5%
SavingsAccount.withdraw() adds a minimum balance check and then calls super.withdraw() to perform the actual deduction. Without super.withdraw(), the Truck would have to duplicate the parent's deduction logic. super.getStatement() reuses the parent's formatted string and appends savings-specific details on top. This is the "extend, don't replace" pattern that makes inheritance maintainable.
Use 3 — super.field — Accessing a Shadowed Parent Field
When a child class declares a field with the same name as a parent field, the child's field shadows the parent's — inside the child, the bare name resolves to the child's field. super.fieldName explicitly accesses the parent's version.
// File: BaseEmployee.java
public class BaseEmployee {
// Package-private — visible to subclass in same package
String department = "GENERAL";
double allowance = 5000.0;
public BaseEmployee() {}
public String getDeptInfo() {
return "Base Department: " + department + " | Allowance: Rs." + allowance;
}
}// File: SeniorEmployee.java
public class SeniorEmployee extends BaseEmployee {
// Shadows the parent's 'department' field — same name, child version
String department = "SENIOR_TECH";
double allowance = 15000.0;
public SeniorEmployee() {
super(); // calls BaseEmployee()
}
public void showDepartments() {
System.out.println("Child department : " + department); // child field
System.out.println("Parent department : " + super.department); // parent field
System.out.println("Child allowance : Rs." + allowance); // child field
System.out.println("Parent allowance : Rs." + super.allowance); // parent field
}
@Override
public String getDeptInfo() {
return "Senior " + super.getDeptInfo(); // calls parent method, which uses parent field
}
}// File: SuperFieldDemo.java
public class SuperFieldDemo {
public static void main(String[] args) {
SeniorEmployee senior = new SeniorEmployee();
senior.showDepartments();
System.out.println();
System.out.println(senior.getDeptInfo());
}
}Output:
Child department : SENIOR_TECH
Parent department : GENERAL
Child allowance : Rs.15000.0
Parent allowance : Rs.5000.0
Senior Base Department: GENERAL | Allowance: Rs.5000.0
Field shadowing is rarely a good design choice — it confuses readers and leads to subtle bugs where the wrong field is accessed. Encapsulation through private fields avoids shadowing entirely because private fields are not visible to the child at all. The super.field use case exists to resolve accidental shadowing but is best avoided through good design.
How super Works Internally
One Object — Two Layers
super does not refer to a different object or a different memory address. The parent and child are two layers of the same object in memory.
Memory layout of new SavingsAccount(...) +--------------------------------------+ | Object header (class reference, etc.)| +--------------------------------------+ | Account fields: | <-- super refers to this layer | accountId : "SAV-001" | | balance : 10000.0 | +--------------------------------------+ | SavingsAccount fields: | <-- this refers to this layer | minimumBalance : 2000.0 | | interestRate : 4.5 | +--------------------------------------+
When you write super.withdraw(amount), the JVM does not create a new object or jump to a different memory location. It calls the Account.withdraw() method bound to the same object in memory, but uses the method resolution of the parent class rather than the child's override.
Constructor Chain with super()
new SavingsAccount("SAV-001", 10000.0, 2000.0, 4.5) called
SavingsAccount() runs first statement: super("SAV-001", 10000.0)
Account() constructor runs:
accountId = "SAV-001"
balance = 10000.0
Account() completes
SavingsAccount() body continues:
minimumBalance = 2000.0
interestRate = 4.5
SavingsAccount() completes
Object is fully initialised
Parent fields are always initialised before child fields. This ordering is guaranteed by the rule that super() must be the first statement — it ensures the parent layer of the object is valid before the child layer is set up.
super vs this — Key Differences
| Aspect | this | super |
|---|---|---|
| Refers to | Current object (current class layer) | Parent class layer of the current object |
| Field access | this.field — current class field | super.field — parent class field |
| Method call | this.method() — current class version | super.method() — parent class version (bypasses override) |
| Constructor call | this() — another constructor in the same class | super() — parent class constructor |
| Can use in static | No | No |
| Position in constructor | this() must be first statement | super() must be first statement |
| Both in one constructor | No — only one first statement allowed | No — same rule |
| When required | When parameter names shadow fields | When parent constructor must be called explicitly, or parent override must be used |
super() vs this() — Constructor Call Comparison
| Aspect | super() | this() |
|---|---|---|
| Calls | Parent class constructor | Another constructor in the same class |
| Purpose | Initialise parent fields | Constructor chaining — avoid duplication |
| Auto-inserted by compiler | Yes — if not written and parent has no-arg constructor | No — never auto-inserted |
| Required when | Parent has only parameterised constructors | You want to delegate to a sibling constructor |
| Position | First statement in child constructor | First statement in any constructor |
| Can coexist in same constructor | No | No |
When super.method() vs Calling method() Directly
| Scenario | Use | Reason |
|---|---|---|
| Child has overridden the method and wants its own behaviour | method() | Calls the child's own override — normal polymorphism |
| Child wants to invoke parent behaviour while extending it | super.method() | Runs parent logic, then child adds to it |
| Child wants to completely replace parent behaviour | method() with full new body | Override without calling super |
| Checking whether the call goes to parent or child | super.method() for parent, method() for child | Explicit disambiguation |
Basic Example
class Animal {
String name;
Animal(String name) {
this.name = name;
}
void speak() {
System.out.println(name + " makes a sound.");
}
}
class Dog extends Animal {
Dog(String name) {
super(name); // calls Animal's constructor to set the name field
}
@Override
void speak() {
super.speak(); // calls Animal's speak() first
System.out.println(name + " barks.");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Rex");
dog.speak();
}
}Output
Rex makes a sound. Rex barks.
- ›
Dog's constructor callssuper(name)as its first statement — this runsAnimal's constructor, which sets the inheritednamefield. - ›
Dogoverridesspeak(), so calling it on aDogruns the child's version. - ›Inside the override,
super.speak()explicitly callsAnimal's originalspeak()before adding the dog-specific line. - ›Without
super.speak(), only "Rex barks." would print — the parent's behaviour would be completely replaced instead of extended.
Best Practices
Always call super() explicitly when the parent has no no-arg constructor
Relying on the compiler to insert super() only works when the parent has a no-argument constructor. When the parent requires arguments — which is most well-designed classes — you must write super(args) explicitly. An explicit super() call is always clearer than relying on implicit insertion, even when the no-arg version exists.
Use super.method() to extend — not replace — parent behaviour
The most valuable pattern is using super.method() when a child wants to add to the parent's behaviour rather than completely replace it. Override getReport() in the child, call super.getReport() to get the parent string, then append child-specific details. This creates a chain where each layer adds its contribution — similar to decorator stacking.
Do not skip parent methods without a clear reason
When a child overrides a method but does not call super.method(), it completely replaces the parent's logic. This is appropriate when the child genuinely needs different behaviour. It is a bug when the parent's logic was needed and simply forgotten. During code reviews, overrides that do not call super are examined to confirm the omission is intentional.
Never access parent fields directly through super.field — use parent methods
super.field accesses parent fields that are not private. This breaks the parent class's encapsulation — the child reaches into parent internal state. Access parent state through the parent's public or protected methods instead. Well-encapsulated parent classes make super.field unnecessary.
Common Mistakes
Mistake 1 — super() Not the First Statement
public class SavingsAccount extends Account {
private double interestRate;
public SavingsAccount(String accountId, double deposit, double rate) {
this.interestRate = rate; // compile error — super() must come first
super(accountId, deposit); // error: call to super must be first statement
}
}Compile error: call to super must be first statement in constructor
Any statement before super() is a compile-time error. Java enforces this because parent fields must be initialised before child fields — you cannot set up the child layer before the parent layer exists.
Mistake 2 — Using super in a Static Method
public class Child extends Parent {
public static void staticMethod() {
// super.someMethod(); // compile error — super not valid in static context
System.out.println("No super available in static methods");
}
}Static methods belong to the class, not to any object instance. super requires a specific object instance to reference the parent layer of — it is meaningless in a static context. The compiler rejects any use of super inside a static method.
Mistake 3 — Forgetting super() When Parent Has No No-Arg Constructor
public class Shipment {
private final String trackingId;
// Only a parameterised constructor — no no-arg version
public Shipment(String trackingId) {
this.trackingId = trackingId;
}
}
public class PriorityShipment extends Shipment {
private String priorityLevel;
public PriorityShipment(String trackingId, String priorityLevel) {
// Missing super(trackingId) — compiler tries to insert super()
// but Shipment has no no-arg constructor
// Compile error: constructor Shipment in class Shipment
// cannot be applied to given types: required String, found no arguments
this.priorityLevel = priorityLevel;
}
}Compile error: constructor Shipment in class Shipment cannot be applied to given types
The fix is to add super(trackingId) as the first statement in PriorityShipment. The compiler's auto-insertion of super() only works when the parent has a no-argument constructor.
Mistake 4 — Calling super() from a Non-Constructor
public class Child extends Parent {
public void someMethod() {
super(); // compile error — super() can only be called from a constructor
}
}super() — the constructor call form — can only appear inside a constructor body, as its first statement. To call a parent method from a non-constructor, use super.methodName(). The two forms are syntactically similar but completely different: super() is a constructor call; super.method() is a regular method call.
Interview Questions
Q1. What are the uses of the super keyword in Java?
super has three uses. super() or super(args) calls the parent class constructor — it must be the first statement in a child constructor and is required when the parent has no no-arg constructor. super.method() calls the parent's version of an overridden method — used when the child wants to extend rather than completely replace the parent's behaviour. super.field accesses a parent field that is shadowed by a child field of the same name — rare in practice since encapsulation through private fields avoids the need for it.
Q2. What is the difference between super and this in Java?
this refers to the current object — it gives access to the current class's own fields, methods, and constructors. super refers to the parent class layer of the current object — it gives access to the parent's fields, methods, and constructor. Both refer to the same object in memory, just to different layers of it. Both are unavailable in static methods. In a constructor, either this() or super() can be the first statement — never both.
Q3. What happens if you do not call super() in a child constructor?
The Java compiler automatically inserts super() — a call to the parent's no-argument constructor — as the first statement. This is transparent if the parent has a no-arg constructor. If the parent has only parameterised constructors and no no-arg constructor, the auto-insertion fails and the compiler reports an error: the child must explicitly call the appropriate parent constructor with super(args). This error is extremely common when extending classes that follow the "always require parameters at construction" design.
Q4. Can super() and this() both appear in the same constructor?
No. Both super() and this() must be the first statement in a constructor, and there can be only one first statement. Java enforces that exactly one of them — or neither — appears at the start. If a constructor chains to a sibling with this(), that sibling is responsible for the super() call. If a constructor calls super() directly, it cannot also call this().
Q5. Why would you call super.method() inside an overriding child method?
When the child wants to reuse the parent's implementation and add to it rather than replace it entirely. This is the "extend, don't replace" pattern. A child getReport() calls super.getReport() to get the parent's formatted string, then appends its own additional details. A child withdraw() validates an extra condition and then calls super.withdraw() to perform the actual deduction. Without super.method(), the child must duplicate the parent's logic or lose it entirely — both are worse outcomes.
Q6. What is the difference between method overriding and calling super.method()?
Method overriding is when a child declares a method with the same signature as a parent method — the child's version replaces the parent's in the method dispatch chain. super.method() is how the child's overriding method explicitly invokes the parent's version from within its own body. They are complementary: overriding changes which method is called by default through polymorphism; super.method() gives the override the ability to delegate upward selectively.
FAQs
What does super mean in Java?
super is a reference to the parent class portion of the current object. It allows a child class to call its parent's constructor (super()), invoke the parent's version of an overridden method (super.method()), or access a parent field that the child has shadowed (super.field).
Is super() mandatory in every child constructor?
Not syntactically — the compiler inserts super() automatically if you omit it, but only if the parent has a no-arg constructor. It is mandatory only when the parent requires constructor arguments. Many teams write super() explicitly in every child constructor as a best practice for clarity, even when the compiler would insert it.
Can you use super in a static method?
No. super requires a specific object instance — it refers to the parent layer of that instance. Static methods belong to the class and have no instance, so super is meaningless and the compiler rejects it.
What is the difference between super.method() and method() in a child class?
method() inside a child class calls the child's own version — the overriding implementation. super.method() bypasses the override and calls the parent's version directly. The difference only exists when the method is overridden in the child. If the method is not overridden, both resolve to the parent's implementation.
Can super access private members of the parent class?
No. private members are invisible to subclasses — super.privateField and super.privateMethod() are compile-time errors. Private fields must be accessed through the parent's public or protected methods. This is why encapsulation through private fields is preferred — it ensures the parent's internal state is always accessed through controlled methods.
How many levels up can super go?
Only one level — to the immediate parent. super.super.method() is not valid Java. If C extends B extends A and C needs to call A's version of a method that B overrides, it cannot do so directly through super. The usual solution is to redesign the hierarchy so B exposes a way to invoke A's logic, or to use a different structure altogether.
Summary
super gives a child class controlled access to its parent layer — the constructor it inherits from, the methods it overrides, and the fields it shadows. Of the three uses, super() in constructors and super.method() in overrides are the ones that appear daily in production code. super.field is a design smell best avoided through encapsulation.
The constructor chain rule — super() must be the first statement — is not arbitrary. It guarantees the parent layer is fully initialised before the child layer is built on top of it. The method call use — super.method() inside an override — is what makes the "extend, don't replace" pattern possible, letting each class in the hierarchy contribute its layer to the result.
For interviews, be ready to explain all three uses of super by name, demonstrate the difference between super and this with the "same object, different layers" mental model, and show why super() must be the first statement in a child constructor. These points appear in both service-based recall questions and product-based design discussions about inheritance hierarchies.
What to Read Next
Learn how a subclass can redefine a parent's method.
Practice Programs
Put this topic into practice — each program has full code, output and a step-by-step explanation you can run online.
Uses super to call a parent class's constructor and its overridden method.
A three-class chain where each class extends the one before it.