Table of Contents

this and super Keywords in Java: A Complete Beginner Guide

  • Last Updated: July 23, 2026
  • By: javahandson
  • Series
img

this and super Keywords in Java: A Complete Beginner Guide

Master this and super keywords in Java with clear examples. Fix parameter shadowing, chain constructors, extend overridden methods, and avoid common mistakes.

1. Introduction

Two small words show up everywhere in Java code. You will meet this and super keywords in Java on your very first day with classes, and they keep appearing for years afterwards.

Both look harmless. Both point at the same object too. Yet they aim in opposite directions, and that difference confuses a lot of beginners.

Here is the short version. The word this looks at the current class. The word super looks one level up, at the parent class.

That single sentence covers maybe seventy percent of what you need. The rest lives in the details, which is what this guide unpacks.

We will cover the ground in this order:

  • How a child object holds both parent and child members at once
  • Every job the this keyword does, with runnable examples
  • Constructor chaining inside one class using this()
  • Every job the super keyword does, from fields to constructors
  • How super() builds an object from the top down
  • Using super with interface default methods
  • A head-to-head comparison table you can memorise
  • The rules the compiler enforces, and the mistakes people repeat

You need only basic class syntax to follow along. If you have written a constructor and used extends once, you are ready.

this and super keywords in Java

2. One Object, Two Viewpoints

Before touching either keyword, get this picture straight. It explains almost every rule that follows.

2.1 What Java Builds When You Write new

Say Dog extends Animal. When you call new Dog(), Java does not create two objects.

It creates one object on the heap. Inside that single block of memory sit the Animal fields and the Dog fields together.

The parent portion gets built first. Then the child portion layers on top of it.

2.2 Where the Keywords Fit

Both keywords reference that one object. Neither creates or copies anything.

What changes is which version of a member the compiler picks:

  • this — start looking from the current class and search upward
  • super — skip the current class and start looking from the parent

Think of a two-storey building. You stand on the first floor by default. Typing super simply walks you downstairs.

Keep that image handy. Every example below is a variation on it.

2.3 A Rule Worth Learning Early

Neither keyword works inside static code. A static method belongs to the class, not to any object.

Since both keywords need an object to reference, the compiler rejects them there. We will revisit this rule later with examples.

3. The this Keyword: Referring to the Current Object

Start with this, since it is the simpler of the two. Inside any instance method or constructor, this holds a reference to the object that call is running on.

You rarely need to write it out. Java assumes it for you most of the time.

3.1 The Invisible this

Look at a plain method with no keyword anywhere:

class Counter {
    int count = 0;
 
    void increment() {
        count++;              // really means: this.count++
    }
}

The compiler expands that line for you. Writing count++ and this.count++ produce identical bytecode.

So why does the keyword exist at all? Because sometimes the short form becomes ambiguous, and then you must be explicit.

3.2 Solving the Name Clash Problem

This is the number one use of this in real code. A constructor parameter often shares its name with a field:

class Student {
    String name;
    int age;
 
    Student(String name, int age) {
        name = name;          // BUG: parameter assigned to itself
        age = age;            // BUG: field stays null and 0
    }
}

That code compiles cleanly. It also does nothing useful, which makes it a nasty bug to spot.

The parameter shadows the field. Both name references point at the parameter, so the field never gets a value.

class Student {
    String name;
    int age;
 
    Student(String name, int age) {
        this.name = name;     // field = parameter
        this.age = age;       // field = parameter
    }
}

Now the left side says this.name, which is unmistakably the field. The right side stays the parameter.

Read it as “my name gets the incoming name.” That phrasing makes the pattern stick.

INTERVIEW INSIGHT
Interviewers often ask why a constructor leaves fields empty. The answer is parameter shadowing. Without this, the compiler resolves both sides to the nearest declaration, which is the parameter. No warning appears because self-assignment is legal Java.

Why Not Just Rename the Parameter?

You could write Student(String studentName, int studentAge) instead. Plenty of older codebases do exactly that.

Modern Java style prefers matching names plus this. The parameter name then documents the field it fills, and IDE autocomplete works better.

3.3 Calling Another Method on the Same Object

You can prefix any instance method call with this. Java assumes it when you leave it out:

class Order {
    double amount;
 
    void checkout() {
        validate();           // same as this.validate()
        this.charge();        // explicit, identical result
    }
 
    void validate() { System.out.println("Validating " + amount); }
    void charge()   { System.out.println("Charging " + amount); }
}

Both call styles behave the same. Most developers skip the prefix here, since it adds length without adding clarity.

3.4 Passing the Current Object Around

Here the keyword becomes genuinely necessary. Sometimes a method must hand the whole object to somebody else.

class Button {
    String label;
 
    Button(String label) {
        this.label = label;
    }
 
    void register(ClickHandler handler) {
        handler.attach(this);      // pass this exact button
    }
}
 
class ClickHandler {
    void attach(Button b) {
        System.out.println("Attached to: " + b.label);
    }
}

Without the keyword you have no way to name the current object. There is no variable holding it inside the method.

Event listeners, builders, and callback registrations all rely on this pattern constantly.

3.5 Returning this for Method Chaining

Return the current object and callers can chain calls together. Builder classes use the trick everywhere:

class Pizza {
    String size = "medium";
    boolean cheese = false;
    boolean olives = false;
 
    Pizza size(String size) {
        this.size = size;
        return this;               // hand the object back
    }
 
    Pizza addCheese() {
        this.cheese = true;
        return this;
    }
 
    Pizza addOlives() {
        this.olives = true;
        return this;
    }
}
 
// Now calls chain naturally:
Pizza order = new Pizza()
        .size("large")
        .addCheese()
        .addOlives();

Each method finishes by returning the same object. The next call in the chain simply continues on it.

You will meet this style in StringBuilder, Stream, and most Spring configuration classes.

3.6 Using this Inside Inner Classes

An inner class has its own this. Reaching the outer object needs a qualified form:

class Outer {
    String label = "outer";
 
    class Inner {
        String label = "inner";
 
        void print() {
            System.out.println(this.label);        // inner
            System.out.println(Outer.this.label);  // outer
        }
    }
}

Write Outer.this to name the enclosing instance. Plain this always means the innermost class.

Anonymous classes and lambdas differ here, and that gap catches people out. A lambda has no this of its own, so this inside a lambda refers to the enclosing class.

4. Constructor Chaining With this()

Add parentheses and the keyword changes job completely. Now this() calls another constructor in the same class.

4.1 The Duplication Problem

Classes often need several constructors. Copy the assignment logic into each one and maintenance gets painful:

class Book {
    String title;
    String author;
    double price;
 
    Book(String title) {
        this.title = title;
        this.author = "Unknown";     // duplicated
        this.price = 0.0;            // duplicated
    }
 
    Book(String title, String author) {
        this.title = title;
        this.author = author;
        this.price = 0.0;            // duplicated again
    }
}

Three fields, two constructors, and already the assignments repeat. Add a fourth field later and you must edit every constructor.

4.2 Routing Through One Constructor

Point the short constructors at the fullest one instead:

class Book {
    String title;
    String author;
    double price;
 
    Book(String title) {
        this(title, "Unknown", 0.0);      // delegate
    }
 
    Book(String title, String author) {
        this(title, author, 0.0);         // delegate
    }
 
    Book(String title, String author, double price) {
        this.title = title;               // assignments live here only
        this.author = author;
        this.price = price;
    }
}

Only the last constructor touches the fields. Everything else supplies defaults and forwards the call.

Add a fifth field tomorrow and you edit exactly one place. That is the payoff.

4.3 Rules for this()

A few restrictions apply, and the compiler enforces every one:

  • The this() call must be the first statement in the constructor
  • A constructor may contain this() or super(), never both
  • You cannot create a cycle, since each constructor must eventually reach a real one
  • The call only works between constructors of the same class
class Broken {
    Broken()      { this(5); }
    Broken(int x) { this(); }     // compile error: recursive invocation
}

Java detects that loop at compile time. No stack overflow at runtime, thankfully.

INTERVIEW INSIGHT
A constructor that calls this() still reaches super() eventually. The chain runs inside the class first, then jumps to the parent from the final constructor. Every object creation ends up calling one parent constructor exactly once.

5. The super Keyword: Reaching the Parent Class

You have seen how this points inward. Now turn the arrow around. The super keyword points at the parent class part of the very same object.

Section 2 described the two-storey building. The keyword super is how you walk downstairs to the floor below.

5.1 A Simple Mental Model

Picture a two-storey building. The ground floor holds parent members. The first floor holds child members. You stand on the first floor by default.

Now say both floors have a room with the same name. Typing the plain name gets you the room on your own floor. Typing super walks you downstairs instead.

That is the whole idea. Nothing more mysterious than that.

One detail matters here. You never create two separate objects. The parent portion and the child portion share a single block of memory on the heap.

So super is not a pointer to some other object sitting elsewhere. It is a compile-time instruction telling Java which version of a member to pick.

5.2 The Three Jobs of super

Java uses this one keyword for three separate tasks. Each has its own syntax:

  • super.field — read or write a parent variable that the child hides
  • super.method() — call the parent version of a method you overrode
  • super(args) — run a parent constructor from a child constructor

Notice the third one has parentheses right after super. Just like this(), that form only works inside a constructor.

The first two forms use a dot. They behave like normal member access, just aimed one level up. You can place them anywhere inside an instance method.

The third form is a different beast entirely. Java treats it as an explicit constructor invocation, and it follows much stricter rules.

6. Using super to Access Parent Fields

Sometimes a child class declares a variable with the same name as one in the parent. Java calls this field hiding. Nothing gets deleted, and both fields still exist.

6.1 The Problem Without super

Look at what happens when names collide. The child name wins by default:

class Vehicle {
    String type = "Generic Vehicle";
}
 
class Bike extends Vehicle {
    String type = "Sports Bike";
 
    void printType() {
        System.out.println(type);        // Sports Bike
        System.out.println(this.type);   // Sports Bike
    }
}

Both lines print the child value. The parent field is still there, but you cannot see it from here.

Why does the child win? The compiler looks for the nearest matching name, starting from the current class. It finds type in Bike and stops searching.

Adding this changes nothing either. Both this.type and a bare type resolve the same way, since this points at the current class view.

6.2 Reaching the Hidden Field

Now add super and the parent value comes back into reach:

class Bike extends Vehicle {
    String type = "Sports Bike";
 
    void printBoth() {
        System.out.println(type);        // Sports Bike
        System.out.println(super.type);  // Generic Vehicle
    }
}
 
public class Demo {
    public static void main(String[] args) {
        new Bike().printBoth();
    }
}

One object, two values, two labels. That is field hiding in action.

Both Fields Really Do Exist

Some people assume the child field overwrites the parent one. Memory tells a different story.

Bike b = new Bike();
Vehicle v = b;                  // same object, parent-typed reference
 
System.out.println(b.type);     // Sports Bike
System.out.println(v.type);     // Generic Vehicle

One object, yet two different answers. The reference type decided which field the compiler picked.

A Quick Warning About Field Hiding

Hiding fields is legal, yet it rarely helps real code. Readers get confused, and bugs slip in quietly.

Prefer a different name, or make the parent field private and expose a getter. Save super.field for cases where you truly cannot rename anything.

INTERVIEW INSIGHT
Fields are not polymorphic. A method call picks the version based on the actual object at runtime. A field access picks the version based on the reference type at compile time. So Vehicle v = new Bike(); v.type prints the parent value, not the child one.

7. Using super to Call Parent Methods

This is the most common use you will meet in daily work. You override a method, yet you still want the parent logic to run.

7.1 Extending Behaviour Instead of Replacing It

Overriding wipes out the parent version for that object. Adding super.method() brings it back as a step inside your own version:

class Payment {
    void process() {
        System.out.println("Validating amount");
        System.out.println("Contacting bank");
    }
}
 
class CardPayment extends Payment {
    @Override
    void process() {
        super.process();                       // run parent steps first
        System.out.println("Charging the card");
    }
}

Calling process() on a CardPayment now prints all three lines. You reused the parent work instead of copying it.

Copy-pasting the parent lines would work too, at first. Yet the moment someone updates Payment, your duplicated version drifts out of sync.

That is the real value here. One call keeps the shared logic in exactly one place, which is where bug fixes belong.

You will spot this pattern all over real frameworks. Servlet code, Android lifecycle methods, and Spring base classes all lean on it heavily.

7.2 Order Matters

You decide where the super call sits. Put it first when the parent sets things up. Put it last when the parent finishes things off.

class AuditedPayment extends Payment {
    @Override
    void process() {
        System.out.println("Writing audit entry");
        super.process();                       // parent runs after our step
        System.out.println("Closing audit entry");
    }
}

Unlike constructors, method calls place no rule on position. You are free here.

7.3 Calling a Parent Method You Did Not Override

If the child never overrides a method, super.method() and plain method() do the same thing. The super prefix adds nothing.

So keep super for the override case. Elsewhere it just adds noise.

A Real Pattern You Will Meet

Base classes often define a template of steps. Child classes plug into that template rather than rewriting it.

class Report {
    void generate() {
        System.out.println("Fetching data");
        System.out.println("Formatting rows");
    }
}
 
class PdfReport extends Report {
    @Override
    void generate() {
        super.generate();
        System.out.println("Rendering to PDF");
    }
}
 
class ExcelReport extends Report {
    @Override
    void generate() {
        super.generate();
        System.out.println("Writing to XLSX");
    }
}

Both children share the fetch and format steps. Neither one duplicates a single line of that logic.

Change the base method later and both reports pick up the change for free. That is inheritance doing useful work.

7.4 super Only Reaches One Level Up

Say you have three classes in a chain: A, then B extends A, then C extends B. Inside C, super refers to B alone.

There is no super.super in Java. You cannot skip a level and jump straight to A:

class A { void greet() { System.out.println("A"); } }
 
class B extends A {
    @Override void greet() { System.out.println("B"); }
}
 
class C extends B {
    @Override void greet() {
        super.greet();          // prints B — legal
        // super.super.greet(); // compile error, not valid Java
    }
}

Java blocks this on purpose. Skipping a middle class would let you bypass logic that B relies on, which breaks encapsulation.

8. Using super() to Call Parent Constructors

Now we reach the form with parentheses. Here super() is not a reference at all. It is a constructor call.

8.1 Why Constructors Chain

A child object contains parent fields. Someone has to initialise them, and only the parent constructor knows how.

Java handles this by chaining. Every constructor calls a constructor above it, until the chain reaches Object at the top.

Think about the risk if this did not happen. Your child constructor might read a parent field before anyone assigned it a value.

Chaining removes that danger completely. By the time your child code runs, every field above it already holds a proper value.

8.2 The Implicit super() You Never Wrote

Here is something most beginners miss. If you write no constructor call at all, the compiler inserts super() for you:

class Animal {
    Animal() {
        System.out.println("Animal constructor");
    }
}
 
class Dog extends Animal {
    Dog() {
        // compiler quietly inserts: super();
        System.out.println("Dog constructor");
    }
}
 
// new Dog() prints:
// Animal constructor
// Dog constructor

Notice the parent line prints first. The chain runs upward, then bodies execute downward.

8.3 Passing Arguments Upward

The inserted call is always the no-argument version. So a parent with only a parameterised constructor forces you to write super() yourself:

class Employee {
    String name;
    int id;
 
    Employee(String name, int id) {
        this.name = name;
        this.id = id;
    }
}
 
class Manager extends Employee {
    String department;
 
    Manager(String name, int id, String department) {
        super(name, id);              // required, no default exists
        this.department = department;
    }
}

Leave out that super call and the code will not compile. The compiler looks for Employee() and finds nothing.

The error message points straight at the constructor, which helps. Still, beginners often try to fix it by assigning parent fields directly in the child.

Avoid that habit. Passing values upward respects whatever validation or setup the parent constructor performs.

8.4 The Rule About Position

Traditionally super() had to be the very first statement in a constructor. That rule kept things safe, since a parent must be ready before child code touches anything.

Java 22 relaxed this through JEP 447. Now you may run some plain statements before the super call, as long as none of them touch the object under construction:

class Order extends Transaction {
    Order(int amount) {
        // Java 22+ allows validation before super(...)
        if (amount <= 0) {
            throw new IllegalArgumentException("Amount must be positive");
        }
        super(amount);
    }
}

Most projects still run older versions, so treat “first statement” as the safe default. Mention the newer rule in interviews only if the topic comes up.

INTERVIEW INSIGHT
A constructor body may contain super(…) or this(…), never both. Using this(…) delegates to another constructor in the same class, and that one eventually reaches super(…). Only one path up the chain is allowed per constructor.

8.5 Watching the Full Chain Run

A three-level example makes the order obvious:

class Grandparent {
    Grandparent() { System.out.println("Grandparent"); }
}
 
class Parent extends Grandparent {
    Parent() { System.out.println("Parent"); }
}
 
class Child extends Parent {
    Child() { System.out.println("Child"); }
}
 
// new Child() prints:
// Grandparent
// Parent
// Child

Each constructor pauses, sends control upward, and resumes only after the parent finishes. Java always builds an object from the top down.

8.6 Mixing this() and super() Across Constructors

A class with several constructors can route them through one another. Only the final one in that chain calls super() directly.

class Product {
    String name;
    double price;
    String category;
 
    Product(String name) {
        this(name, 0.0);              // delegate within the class
    }
 
    Product(String name, double price) {
        this(name, price, "General"); // delegate again
    }
 
    Product(String name, double price, String category) {
        super();                      // finally reaches Object
        this.name = name;
        this.price = price;
        this.category = category;
    }
}

This keeps assignment logic in a single constructor. The shorter ones simply fill in sensible defaults.

Follow the arrows and you will see each constructor calls exactly one other. No constructor ever runs twice for a single object.

9. super With Interface Default Methods

Java 8 gave interfaces default methods, which come with a body. That created a fresh naming problem, and a special super syntax to fix it.

9.1 The Ambiguity Problem

Suppose two unrelated interfaces declare the same default method. A class implementing both leaves the compiler stuck:

interface Walkable {
    default void move() { System.out.println("Walking"); }
}
 
interface Swimmable {
    default void move() { System.out.println("Swimming"); }
}
 
// Will not compile: which move() should Duck inherit?
class Duck implements Walkable, Swimmable { }

Java refuses to guess. A class that implements two independent interfaces with the same default method signature must override that method itself.

People call this the diamond problem. Older languages allowed multiple inheritance of state, which created messy ambiguity.

Java sidestepped that for years by banning multiple class inheritance. Default methods brought a milder version of the issue back, so the language added an explicit escape hatch.

9.2 Picking a Winner With InterfaceName.super

The fix uses a qualified form of super. You name the interface, then reach its default body:

class Duck implements Walkable, Swimmable {
    @Override
    public void move() {
        Walkable.super.move();      // choose the walking version
        System.out.println("...then quacking");
    }
}

Plain super would be meaningless here, because there are two candidates. The interface name removes all doubt.

9.3 Which Version Wins Automatically

Java does resolve some conflicts on its own. Three rules apply, checked in order:

  • A method inherited from a class beats any interface default with the same signature
  • A more specific sub-interface beats the parent interface it extends
  • When neither rule settles it, the class must override and choose explicitly

Classes rank above interfaces, and a derived sub-interface ranks above the interface it extends. Only the third case forces your hand.

INTERVIEW INSIGHT
The class-wins rule is a favourite interview question. If a class extends a parent with move() and also implements an interface with a default move(), the parent class version runs. To use the interface body instead, you must override and call InterfaceName.super.move() by hand.

9.4 Seeing the Class-Wins Rule in Code

The rule sounds abstract until you run it. Here a class and an interface both offer greet():

interface Friendly {
    default void greet() { System.out.println("Hello from interface"); }
}
 
class Base {
    public void greet() { System.out.println("Hello from class"); }
}
 
class Person extends Base implements Friendly {
    // no override needed — the class version wins automatically
}
 
// new Person().greet()  prints:  Hello from class

No compile error appears, because Java already knows which one to pick. The class method simply outranks the default.

Want the interface version instead? Override greet() in Person and call Friendly.super.greet() explicitly.

10. Rules and Restrictions for Both Keywords

A handful of hard rules govern super. Break one and the compiler stops you immediately.

10.1 Neither Keyword Works in Static Context

Static methods belong to the class, not to any object. Since super needs an object to point at, the two cannot mix:

class Parent { void show() { System.out.println("Parent"); } }
 
class Child extends Parent {
    static void broken() {
        // super.show();   // compile error: non-static context required
    }
}

Both lines fail for the same reason. A static method has no object, so neither keyword has anything to point at.

A static method can still work with object members, though. Just accept an object as a parameter, then call methods on it normally.

10.2 No super Inside an Interface Body

An interface has no superclass, so plain super has nothing to reference there. Only the qualified InterfaceName.super form works, and only from an implementing class.

10.3 Constructor Calls Belong Only in Constructors

The parenthesised forms belong to constructors only. Writing super() or this() inside an ordinary method fails to compile.

Beginners sometimes try this when constructor logic looks reusable elsewhere. Move that logic into a normal method instead, then call it from both places.

10.4 Private Members Stay Out of Reach

A child class does not inherit private members. Therefore super cannot reach them either:

class Account {
    private double balance = 100;
    protected double getBalance() { return balance; }
}
 
class Savings extends Account {
    void check() {
        // System.out.println(super.balance); // error: balance is private
        System.out.println(super.getBalance()); // fine: protected method
    }
}

Route your access through a protected or public method, as shown above.

10.5 Both Keywords Inside Anonymous and Inner Classes

An anonymous class can call super too. It refers to whatever type you extended or implemented on the spot.

Thread worker = new Thread() {
    @Override
    public void run() {
        System.out.println("Before parent run");
        super.run();          // Thread's own run()
    }
};

Inner classes work slightly differently. Plain super still means the inner class parent, not the outer class.

To reach the enclosing instance, use Outer.this as shown back in section 3.6. Plain this always means the innermost class.

Lambdas break the pattern. A lambda has no this of its own, so this inside one refers to the enclosing class instead.

10.6 A Quick Rules Summary

SituationAllowed?Reason
this.field in an instance methodYesAn object exists to reference
this() as first statement in a constructorYesDelegates within the same class
return this from a methodYesEnables method chaining
super.field in an instance methodYesReads the hidden parent variable
super() in a constructorYesNormal constructor chaining
this() and super() in one constructorNoOnly one delegation path is allowed
super() or this() in a regular methodNoConstructor calls are constructor-only
Either keyword anywhere staticNoNo object is present
super.super.method()NoJava exposes one level only
super.privateFieldNoPrivate members are never inherited

11. Common Mistakes Beginners Make

These slip-ups show up again and again. Spotting them early saves hours of confusion.

11.1 Forgetting the Parent Has No Default Constructor

Once you add any constructor to a class, Java stops supplying the free no-argument one. Child classes then break with a puzzling message.

Either add an explicit super(…) call in the child, or give the parent a no-argument constructor.

The compiler message usually reads something like “constructor Parent in class Parent cannot be applied to given types.” That wording confuses people, since they never wrote any constructor call.

Remember the hidden super() insert and the message makes sense at once.

11.2 Expecting Fields to Behave Like Methods

Polymorphism covers methods, not variables. Many people assume both follow the same rule, and their output surprises them:

class Parent { String label = "P"; String get() { return "P"; } }
class Child extends Parent {
    String label = "C";
    @Override String get() { return "C"; }
}
 
Parent ref = new Child();
System.out.println(ref.label);   // P  (reference type decides)
System.out.println(ref.get());   // C  (object type decides)

Read those two lines carefully. The difference catches out plenty of experienced developers too.

11.3 Writing super() and this() Together

A constructor can delegate one way only. Trying both produces an immediate compile error, since each would want to be the first call.

11.4 Building Infinite Recursion by Accident

Watch this trap. Calling the overridden name instead of super.name loops forever:

class Logger {
    void log() { System.out.println("base log"); }
}
 
class TimestampLogger extends Logger {
    @Override
    void log() {
        // log();        // WRONG: calls itself, StackOverflowError
        super.log();     // RIGHT: calls the parent version
        System.out.println("with timestamp");
    }
}

One missing keyword turns a helpful override into a crash. Always double-check that prefix.

11.5 Calling an Overridable Method From a Constructor

This one bites hard. A parent constructor that calls an overridable method runs the child version, before child fields are ready:

class Base {
    Base() {
        init();                    // dangerous: subclass version runs
    }
    void init() { System.out.println("Base init"); }
}
 
class Derived extends Base {
    String value = "ready";
 
    @Override
    void init() {
        System.out.println("Derived init, value = " + value);
    }
}
 
// new Derived() prints:  Derived init, value = null

The field prints as null. Base ran first, and Derived had no chance to assign value yet.

Keep constructors simple to avoid this. Mark such helper methods private or final so nobody can override them.

12. this vs super: A Direct Comparison

Both keywords are now covered separately. Placing them side by side makes the boundary obvious.

12.1 The Full Comparison Table

Aspectthissuper
Refers toCurrent object, current class viewParent class part of the same object
Field accessthis.name reads the current class fieldsuper.name reads the parent field
Method callthis.show() runs the current versionsuper.show() runs the parent version
Constructor formthis() calls another constructor in the same classsuper() calls a parent constructor
Main use for fieldsFixing parameter shadowingReading a field the child hides
Main use for methodsPassing the object, chaining callsExtending an overridden method
Can be returnedYes, enables method chainingNo, it is not a real reference value
Inner class formOuter.thisInterface.super
Works in static codeNoNo
Inserted automaticallyNoYes, super() is added if you write nothing

12.2 Seeing Both in One Class

A single example puts every use together:

class Vehicle {
    String type = "Vehicle";
 
    Vehicle(String type) {
        this.type = type;              // this: fix shadowing
    }
 
    void describe() {
        System.out.println("A " + type);
    }
}
 
class Car extends Vehicle {
    String type = "Car";
 
    Car() {
        this("Generic Car");           // this(): delegate in-class
    }
 
    Car(String type) {
        super("Four Wheeler");         // super(): parent constructor
        this.type = type;              // this: fix shadowing again
    }
 
    @Override
    void describe() {
        super.describe();              // super: parent method
        System.out.println("Specifically a " + this.type);
    }
}

Trace the flow for new Car(). The no-argument constructor delegates, the parent constructor runs, then the child assignment happens.

Calling describe() prints the parent line first, then the child line. Both keywords cooperate on the same object.

12.3 The One-Line Summary

Strip away the detail and you get a simple pair of statements.

Use this when you mean the object you are inside right now. Use super when you mean the version that came before yours.

Everything else in this article follows from those two sentences.

13. When Should You Use Each Keyword?

Knowing the syntax is one thing. Knowing when to reach for it matters more.

13.1 Good Reasons to Use Each

  • A constructor parameter shares its name with a field, so you write this.field = param
  • Several constructors share setup logic, so the short ones delegate with this(args)
  • A method must hand the current object to a listener or collaborator
  • You want fluent chaining, so each method returns this
  • You override a method and want the parent behaviour plus something extra
  • Your parent class needs constructor arguments to set up its own fields
  • Two interfaces clash on a default method and you must pick one

13.2 Signs You Should Rethink the Design

  • You hide a parent field just to reuse a convenient name
  • You sprinkle this everywhere when no name clash exists, which only adds noise
  • You wish super.super existed, which usually means the hierarchy is too deep
  • Every child method starts with a long chain of super calls

Deep inheritance trees create fragile code. Composition often reads better, so weigh that option before adding another level.

A useful rule of thumb: two or three levels of inheritance is plenty for most business code. Beyond that, tracing behaviour becomes genuinely painful.

Ask a simple question before extending a class. Does the child truly represent a kind of the parent, or do you just want to borrow a few methods? Borrowing is a job for composition.

13.3 A Quick Decision Guide

Your goalReach for
Assign a parameter to a field of the same namethis.field = param
Reuse constructor logic inside one classthis(args)
Hand the current object to another methodthis
Enable fluent method chainingreturn this
Add steps around inherited logicsuper.method() in your override
Initialise parent fields with valuessuper(args) in the child constructor
Pick between clashing interface defaultsInterfaceName.super.method()
Reuse a few unrelated helper methodsComposition, not inheritance

Most day-to-day super usage falls in the first two rows. The rest show up occasionally, and the last row is a warning sign.

14. Interview Questions

Q: What is the difference between this and super in Java?

A: Both reference the same object, but the viewpoint differs. The keyword this resolves members starting from the current class, while super starts from the parent class. Only the resolution changes, not the object.

Q: Why do we need this in a constructor?

A: A constructor parameter often shares its name with a field, which shadows that field. Writing this.name = name assigns the parameter to the field. Without it, the line becomes a self-assignment and the field keeps its default value.

Q: What is the difference between this() and super()?

A: The call this() invokes another constructor in the same class, while super() invokes a parent class constructor. Both must be the first statement, so a single constructor can contain one or the other but never both.

Q: Why do builder classes return this?

A: Returning the current object lets callers chain method calls together. Each method finishes by handing the same object back, so the next call continues on it. StringBuilder and Stream both use this pattern.

Q: Can this or super be used inside a static method?

A: No. A static method belongs to the class rather than any object, and both keywords need an object to reference. Pass an object as a parameter instead if the static method needs instance members.

Q: How do you access the outer class instance from an inner class?

A: Use the qualified form Outer.this, since plain this always refers to the innermost class. Lambdas differ here, because a lambda has no this of its own and inherits the enclosing class instance.

Q: What happens if you do not write super() in a constructor?

A: The compiler inserts a no-argument super() automatically. If the parent class has no no-argument constructor, compilation fails and you must call super(args) yourself.

Q: Why must super() be the first statement in a constructor?

A: The parent portion of the object must be initialised before any child code touches it. Java 22 relaxed this through JEP 447, allowing plain statements before super() as long as they do not access the object under construction.

Q: Can you use super.super.method() in Java?

A: No. Java exposes only one level up the hierarchy. Skipping a middle class would bypass logic that class depends on, which breaks encapsulation, so the language forbids it.

Q: Are fields polymorphic in Java like methods are?

A: No. Method calls resolve at runtime based on the actual object type, while field access resolves at compile time based on the reference type. So Parent ref = new Child(); ref.label reads the parent field.

Q: How do you resolve conflicting default methods from two interfaces?

A: Override the method in your class and pick a version using InterfaceName.super.methodName(). Java refuses to guess when two unrelated interfaces declare the same default method signature.

Q: If a class and an interface both define the same method, which one wins?

A: The class method wins, since classes rank above interfaces in the resolution rules. To use the interface body instead, override the method and call InterfaceName.super.method() explicitly.

15. Conclusion

Let us pull everything together. Both keywords reference the same object, and only the viewpoint separates them.

The keyword this means the object you are working inside. Use it to fix parameter shadowing, to pass the object elsewhere, and to return for chaining. Add parentheses and this() reuses another constructor in the same class.

The keyword super means the parent version. Reach for super.field when a child hides a variable. Call super.method() to extend an override rather than replace it. Pass super(args) to hand values up the constructor chain.

Remember the shared limits too. Static code has neither keyword, private members stay out of reach, and Java never offers a second hop upward.

Get these rules under your belt and inheritance stops feeling like guesswork. Your constructors initialise cleanly, and your overrides do exactly what you intended.

Further Reading

Leave a Comment