Course contents

The this keyword in Java

Everything this does in Java: disambiguating fields, constructor chaining with this(...), passing and returning this for fluent APIs, this in lambdas versus anonymous classes, and the this-escape concurrency bug in constructors.

PremiumOften askedLesson15 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: the word "my" on a shared form
  2. this under the hood
  3. Real world: leaking this from a constructor
  4. Advanced: lambdas, anonymous classes and other edge cases
  5. How to say it in the interview

👉 What is the

this keyword? this is a reference to the object the current instance method or constructor is running on. Inside order.applyDiscount(10), this is order; inside refund.applyDiscount(10) the same code sees this as refund. You use it to reach your own fields when a parameter has the same name, to call another constructor with this(...), and to hand yourself to other code.

this looks like the smallest keyword in the language, and interviewers know that. The warm-up version is "why do we write this.id = id?". The follow-ups get serious quickly: what this(...) does to initialisation order, why returning this breaks under inheritance, what this means inside a lambda versus an anonymous class, and the senior one, how a constructor that leaks this can produce a half-built object on another thread.

What you’ll learn

  • Explain this as the hidden receiver in local slot 0 (aload_0) and why static code has none
  • Fix the shadowing bug in amount = amount and use this.field deliberately
  • Chain constructors with this(...) and say exactly where field initialisers run in the chain
  • Return this for fluent APIs and keep chaining in subclasses with a self-type generic
  • Predict what this means in a lambda versus an anonymous class, and use Outer.this
  • Spot and fix this escape from a constructor, and explain why it breaks final-field guarantees (JLS 17.5)

For this lesson, we'll cover every job this does, what it compiles to, and the bugs it causes when used carelessly.

Below the line (out of scope)

The 30-second answer

this is a final reference to the current object, available in instance methods, constructors and instance initialisers, and never in a static context. The JVM passes it as a hidden first argument, stored in local slot 0. You use it for four things: disambiguating a field from a same-named parameter (this.amount = amount), chaining constructors with this(...) as the first statement, passing the current object to other code (registry.add(this)), and returning it for fluent APIs (return this;). Inside a lambda, this means the enclosing object, because lambdas don't create a new scope; inside an anonymous class it means the anonymous object itself. The classic bug is letting this escape from a constructor, for example by registering a listener, because another thread can then see the object before its fields are set.

Interview radar

Asked very often: Why do we write this.x = x in a constructor, and what is the difference between this and this()? Senior rounds probe: What this refers to in a lambda versus an anonymous class, and why leaking this from a constructor is unsafe under the Java Memory Model. Production angle: An event listener registered in its own constructor that throws NullPointerException on a field the constructor definitely sets, but only under load.

01Picture it first: the word "my" on a shared form

Imagine every employee at a company fills in the same printed form: "Ship my laptop to my desk." The form is written once. The word "my" means a different person depending on who is holding the form at that moment.

A method in Java works the same way. The bytecode for applyDiscount exists once in the class. Every call needs to know whose fields it should touch, so the JVM hands the method a hidden argument: the object you called it on. That hidden argument is this. The diagram shows two calls running the same code with different objects in slot 0.

Fig. 1

Two Order objects on the heap; the call a.applyDiscount(10) creates a frame whose local slot 0 holds a reference to the first order, and b.applyDiscount(10) creates a frame whose slot 0 points to the second, while both frames run the same method bytecode stored once in the class

Two Order objects on the heap; the call a.applyDiscount(10) creates a frame whose local slot 0 holds a reference to the first order, and b.applyDiscount(10) creates a frame whose slot 0 points to the second, while both frames run the same method bytecode stored once in the class

Notice three things:

  • One method, many receivers. Code isn't copied per object; this is what makes shared code act on individual state.
  • this lives in slot 0 of the frame. Parameters start at slot 1 in an instance method.
  • Static methods have no slot for it. That's why this is a compile error inside static code: there's no object to refer to.

02this under the hood

Disambiguating fields from parameters

Try it yourself first

Before reading on, predict what new Invoice("INV-7", 1200).amount() returns.

public class Invoice {
    private final String number;
    private long amount;

    public Invoice(String number, long amount) {
        this.number = number;   // field = parameter
        amount = amount;        // parameter = parameter, field untouched
    }

    public long amount() { return amount; }   // no clash here, this. is optional
}

It returns 0. Inside the constructor, the parameter amount shadows the field, so amount = amount assigns the parameter to itself. The field keeps its default. Notice:

  • this.amount always means the field. The bare name means the nearest declaration in scope, which is the parameter.
  • final would have caught it. Mark amount as final and javac fails with "variable amount might not have been initialized". That's one more reason to prefer final fields.
  • In amount() there's no clash, so return amount; and return this.amount; compile to the same bytecode.

Here's what an instance method compiles to. javap -c on amount() shows the hidden argument being loaded:

aload_0          // push this (local slot 0)
getfield #13     // Field amount:J
lreturn

Every unqualified field access in an instance method is really this.field. The compiler writes the aload_0 for you.

Constructor chaining with this(...)

this(...) (with parentheses) is a different feature. It calls another constructor of the same class, so you keep the real logic in one place.

public class Order {
    private final long id;
    private final String currency;
    private final List<String> lines = new ArrayList<>();   // field initialiser

    public Order(long id) {
        this(id, "INR");                       // must be the first statement
        System.out.println("short ctor done");
    }

    public Order(long id, String currency) {
        // implicit super() here
        this.id = id;
        this.currency = Objects.requireNonNull(currency);
        System.out.println("full ctor done");
    }
}

new Order(42);
// prints: full ctor done
// prints: short ctor done

The chain goes up through this(...) to the constructor that calls super(...), then runs back down. The diagram shows where field initialisers run, which is the part interviewers test.

Fig. 2

new Order(42) calls Order(long), which delegates with this(id, &quot;INR&quot;) to Order(long, String); that one calls super() up to Object, then runs the field initialiser for lines, then its own body, and only then does control return to the rest of Order(long)

new Order(42) calls Order(long), which delegates with this(id, &quot;INR&quot;) to Order(long, String); that one calls super() up to Object, then runs the field initialiser for lines, then its own body, and only then does control return to the rest of Order(long)

Notice:

  • Field initialisers run once, in the constructor that calls super. javac copies lines = new ArrayList<>() into Order(long, String) only, never into Order(long), so chaining doesn't create two lists.
  • this(...) and super(...) are mutually exclusive and must be the first statement in Java 21. A constructor can call one or the other, not both.
  • Cycles are caught at compile time. If Order(long) calls this(id, "INR") and that calls this(id), javac reports "recursive constructor invocation".
  • You can't use this in the arguments. this(id, this.defaultCurrency()) fails because the object isn't initialised yet. Static methods are fine: this(id, defaultCurrency()) works if defaultCurrency is static.

Java 25 relaxed the first-statement rule with flexible constructor bodies (JEP 513, previewed from Java 22): you can validate arguments before this(...) or super(...), as long as you don't touch this. On Java 21, do that validation in a static helper called inside the argument list.

Passing this to other code

Sometimes an object needs to give itself away: to register as a listener, to compare against another object, or to lock on itself.

@Override
public boolean equals(Object o) {
    if (this == o) return true;                  // same object, skip field checks
    if (!(o instanceof Order other)) return false;
    return id == other.id && currency.equals(other.currency);
}

public void attachTo(OrderBus bus) {
    bus.subscribe(this);                         // safe: the object is fully built
}

Passing this is fine once construction is complete. synchronized (this) also works, but it exposes your lock to any caller who holds a reference to your object, so in library code I prefer a private final Object lock = new Object();.

Returning this for fluent APIs

Return this from a method and callers can chain calls. StringBuilder.append and most builders do this.

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • Real world: leaking this from a constructor
  • Advanced: lambdas, anonymous classes and other edge cases
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicClasses & objects: interview questions & scenarios
Further reading (8)