Java super Keyword
›Short versionOpen if you only have a minute.
- super.method(...) calls the superclass method on this same object. Use it when an override wants the original body.
- super(...) calls a superclass constructor and must be the first statement.
- If you write neither super(...) nor this(...), the compiler inserts super() and requires a no-argument superclass constructor.
- this(...) and super(...) cannot both start the same constructor. One constructor in the chain makes the superclass call.
- A subclass field with the same name hides the superclass field. super.field reads the hidden one. Fields do not override.
- A bare call to the overridden method from inside the override calls the subclass again.
The savings account wants a daily limit, and it still wants the original check that the amount is actually in the account. is how the override reaches that original check without pretending the superclass code was copied into the subclass.
The superclass constructor runs first
A subclass object is not ready until its superclass part is initialized. The is that order, and is how you pass the arguments upward.
public class SavingsAccount extends Account {
private final int dailyLimit;
public SavingsAccount(int opening) {
this(opening, 1_000);
}
public SavingsAccount(int opening, int dailyLimit) {
super(opening);
if (dailyLimit <= 0) {
throw new IllegalArgumentException("dailyLimit");
}
this.dailyLimit = dailyLimit;
}
}new SavingsAccount(80) enters the one-argument constructor, which calls this(opening, 1_000). That second constructor calls super(opening), so Account checks the opening balance before dailyLimit is stored. The one-argument constructor cannot also call super. Its first line is already this(...).
Account has no no-argument constructor in this design. Forgetting super(opening) means the compiler inserts super(), and the file fails to compile. That failure is useful. An opening balance would otherwise never be set by the subclass.
The superclass method, on this object
The adds a limit and then asks Account to move the money. The receiver is the savings account the caller already has. super only selects Account's body.
@Override
public void withdraw(int amount) {
if (amount > dailyLimit) {
throw new IllegalArgumentException("daily limit");
}
super.withdraw(amount);
}Writing withdraw(amount) there, without super, calls the override again. The limit check runs, then it calls itself, until the stack overflows. The superclass body is what actually subtracts from the balance, assuming Account kept that field private and did the subtraction in withdraw.
Two fields with one name
A is easy to create and hard to read. Both fields exist on the object.
class Account {
String label = "account";
}
class SavingsAccount extends Account {
String label = "savings";
void print() {
System.out.println(label); // savings
System.out.println(super.label); // account
}
}Account a = new SavingsAccount(); then a.label reads Account's field, because field access uses the compile-time type. That surprise is a good reason to keep fields private and expose one method. super can still reach a hidden field from inside the subclass when you are untangling old code. It is a weak reason to declare the second field.
$ javac Account.java SavingsAccount.java$ java SavingsAccount
SavingsAccount overrides withdraw and its first line is withdraw(amount). What happens when a caller withdraws 10?
The override calls itself. Account's withdraw never runs, so the balance does not change, and the call recurses until the stack overflows. The first line that should reach the superclass is super.withdraw(amount), after any extra subclass check.