Command Palette

Search for a command to run...

PHASE 4Beginner ~26 min· topic 4 of 12

Topic 4.4

The this Keyword

In one line

this is a reference to the object the current method or constructor is running on. You use it to tell a field from a parameter with the same name, to pass or return the current object, and (as this(...)) to call another constructor.

Think of it like this

In a classroom, every pupil says "my bag". The words are the same, but each "my" means a different person, depending on who is speaking. In Java, this is the method's "my": inside rex.bark() it means Rex, and inside bella.bark() the very same code means Bella.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

`this`
A reference to the current object: the one the method was called on, or the one being constructed.
Shadowing
When a local variable or parameter has the same name as a field, the closer name wins and hides the field inside that block.
Disambiguate
Make clear which of two things with the same name you mean. this.x means the field, x means the parameter.
Fluent interface
A style where methods return this, so you can write several calls in one chain: a.b().c().d().
Method chaining
Calling a method on the result of the previous call, in one expression.
Self-assignment
Assigning a variable to itself, like x = x;. It does nothing, and it's usually a bug.

Step by step

01The same code, a different "me" each time

void describe() { System.out.println(this.name); } runs on whatever object you call it on. rex.describe() sets this to Rex; bella.describe() sets this to Bella.

Writing name alone is the same as this.name when nothing else is called name. The compiler adds the this. for you. You only *need* to write it when there's a conflict.

Main.javawhole filejava
class Dog {
    String name;

    void describe() {
        System.out.println("I am " + this.name);   // same as: name
    }
}

02Shadowing: when a parameter hides a field

Good parameter names often match field names: a constructor that sets name naturally takes a parameter called name. Inside that constructor, the parameter is the nearest declaration, so name means the parameter.

name = name; assigns the parameter to itself. It compiles, does nothing, and the field keeps its default null. Many IDEs and linters flag it, but javac doesn't.

this.name = name; says: the field of this object gets the parameter's value. This is the standard Java idiom.

Shadowing: when a parameter hides a fielddiagram
Rendering diagram…

03Passing this: an object hands itself over

Sometimes an object needs to give a reference to itself to someone else: a student enrolling in a course, a button registering with a window. Inside Student.enrol(Course c), c.add(this) passes the current student.

Be careful doing this inside a constructor: the object isn't finished yet, and whoever receives this might use it too early (see Pro notes).

Main.javawhole filejava
class Student {
    String name;

    void enrol(Course c) {
        c.add(this);     // give the course a reference to me
    }
}

04Returning this: fluent chaining

If a method ends with return this; and declares the class as its return type, the caller gets the same object back and can call another method on it straight away.

new Order().add("tea").add("samosa").discount(10) is three calls on one Order object. StringBuilder.append works exactly like this (Topic 6.3).

Main.javawhole filejava
Order add(String item) {
    items += item + " ";
    return this;          // hand back the same object
}

05No this in static code

static methods belong to the class, not to an object (Topic 4.6). When main runs, no Main object exists, so there's nothing for this to refer to.

That's also why a static method can't use instance fields without naming an object: count really means this.count, and this doesn't exist there.

terminal
$ javac Main.java
── expected output ──
Main.java:4: error: non-static variable this cannot be referenced from a static context
System.out.println(this.count);
^
1 error

06What this is in the bytecode

For an instance method, the JVM puts the receiver into local variable slot 0 before the method runs. this compiles to aload_0. Parameters start at slot 1.

That's also why this can never be null: calling a method on a null reference throws NullPointerException *before* the method starts, so a running instance method always has a real object in slot 0.

Try it yourself

  1. 1

    Find the silent bug

    In "Shadowing bug vs the fix", rename BuggyDog's parameters to n and a (and the body to name = n; age = a;). Predict the output, then run. Now this. is unnecessary. Why?

  2. 2

    Break the chain

    In the fluent Order example, change discount to return void. Read the compiler error you get on the chain, and explain which call broke it.

  3. 3

    Count the enrolments

    Add a field int courses to Student and increment it in enrol using this.courses++. Enrol Asha in two courses and print her count.

Code & diagrams

Shadowing bug vs the fix New tab
Sign in to run this example in your browser.

Expected output

buggy: null, 0
good:  Rex, 3
Returning this for a fluent API New tab
Sign in to run this example in your browser.

Expected output

tea samosa samosa = 45
same object? true
tea samosa samosa water = 55
Passing this to another object New tab
Sign in to run this example in your browser.

Expected output

Core Java: Asha Ben
first enrolled is asha? true

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Forget this. in a constructor

In a constructor Dog(String name), write name = name; instead of this.name = name;.

terminal
$ java Main
── what you'll see ──
buggy: null, 0

Break #2

Use this inside main

Add a field int count; to Main and write System.out.println(this.count); inside main.

terminal
$ javac Main.java
── what you'll see ──
Main.java:4: error: non-static variable this cannot be referenced from a static context
System.out.println(this.count);
^
1 error

Myth vs fact

Myth

You must always write this. before fields.

Fact

Only when a local variable or parameter with the same name shadows the field. Otherwise the compiler adds this. for you. Some teams write it always for clarity; that's style, not a rule.

Myth

this can be null.

Fact

Never. A call on a null reference throws before the method starts, so a running instance method always has a real object as this.

Myth

this() and this. are the same feature.

Fact

this.x reads a member of the current object. this(...) calls another constructor and is allowed only as the first statement of a constructor.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    In bytecode this is local slot 0 (aload_0) in every instance method and constructor; parameters start at slot 1. Static methods have no slot reserved for it, which is the low-level reason this is illegal there.

  • ▸

    **Escaping this** from a constructor (starting a thread with it, publishing it to a static list, registering a listener) lets other code see a partly initialised object. The JLS 17.5 guarantee that other threads see correctly initialised final fields only holds if this doesn't escape before the constructor finishes. Use a static factory that constructs first and registers afterwards.

  • ▸

    In a lambda, this refers to the enclosing instance; in an anonymous class it refers to the anonymous object. This is one of the real semantic differences between the two (Phase 11), and why lambdas capture this when they use instance members (which can keep the outer object alive).

  • ▸

    Fluent setters that return this don't work well with inheritance: a parent's name() returns the parent type, so a child's methods disappear from the chain. Builders solve it with a self-type generic (B extends Builder<B>) or by keeping builders final.

Remember this

  1. 1

    this is a reference to the current object: the receiver the method was called on, or the object being built in a constructor. It's not a variable you declare; the compiler provides it in every instance method and constructor, as local slot 0 in the bytecode.

  2. 2

    The most common use is disambiguation. In Point(int x, int y) { this.x = x; }, the parameter x shadows (hides) the field x, so plain x means the parameter. this.x says "the field of this object". Forget this. and you write x = x;, assigning the parameter to itself: the field silently stays 0.

  3. 3

    You can pass this to another method (registry.add(this)) when an object needs to hand itself over, and you can return this from a method so calls can be chained: builder.name("Asha").age(30).city("Pune"). This is called a fluent interface.

  4. 4

    this(...) (with parentheses) is a different thing: a call to another constructor of the same class, allowed only as the first statement of a constructor (Topic 4.3).

  5. 5

    static methods have no this, because they don't run on any object. Using this in main is a compile error: non-static variable this cannot be referenced from a static context.

  6. 6

    this is final: you can't assign to it (this = other; doesn't compile). Inside an inner class, plain this means the inner object and Outer.this means the enclosing one (Topic 5.13). Inside a lambda, this means the enclosing object, not the lambda (Phase 11).

Explain it without notes

01

What does this refer to inside an instance method, and inside a constructor?

02

Why does name = name; in a constructor compile but not work?

03

Give two reasons to pass or return this, with an example of each.

04

Why can't static methods use this?

Practice

01

Write a class Person with fields name and age, a constructor that uses parameters with the same names, and a method isOlderThan(Person other) that uses this.age and other.age. Show it with two people.

02

Write a fluent class Text with methods add(String s), space() and upper() that each return this, and a toString() returning the built text. Build HELLO WORLD with one chain.

03

Write a class Node with int value and Node next, and a method Node link(Node n) that sets this.next = n and returns n. Build the list 1 -> 2 -> 3 in one chain and print it.

Trade-offs

  • ↔

    Writing this. everywhere makes field access obvious when reading, but adds noise. Most style guides use it only where needed (constructors and setters with matching parameter names).

  • ↔

    Fluent return this APIs read beautifully for builders and configuration, but they hide that the same object is being mutated, which surprises callers who expected a new object (compare immutable String, whose methods return new strings, Topic 4.11).

Done when you can

  • Done when you can explain what this refers to in a method and in a constructor.

  • Done when you can spot and fix the x = x; shadowing bug.

  • Done when you can write a fluent API with return this.

  • Done when you can explain why this doesn't exist in static methods.

  • Done when you know this(...) calls a constructor and this.x reads a member.