this Keyword

Su Suriya Ravichandran Updated 14 Nov 2026
8 min read ·Lesson 47 of 133

Inside an instance method or constructor, this is a reference to the current object: the object whose method is running or which is being constructed. It is how an object refers to itself. this is used to tell fields apart from parameters with the same name, to call another constructor, to pass the current object to other code, and to return the object for method chaining.

What this Refers To

public class Lamp {
    private boolean on;

    public void toggle() {
        this.on = !this.on;
    }
}
Lamp kitchen = new Lamp();
Lamp hallway = new Lamp();

kitchen.toggle();    // inside toggle, this == kitchen
hallway.toggle();    // inside toggle, this == hallway

There is only one copy of toggle's code, but every call runs on a specific object. The JVM passes that object as a hidden argument, and this is the name for it. When the method reads this.on, it reads the field of whichever lamp the method was called on.

Writing this. before a field is usually optional. on = !on; means exactly the same thing, because the compiler resolves an unqualified field name to the current object's field. this becomes required in the situations below.

Distinguishing Fields from Parameters

When a parameter or local variable has the same name as a field, the local name shadows the field: the simple name refers to the parameter. this.name refers to the field.

public class Employee {
    private String name;
    private double salary;

    public Employee(String name, double salary) {
        this.name = name;        // field = parameter
        this.salary = salary;
    }

    public void setSalary(double salary) {
        if (salary < 0) throw new IllegalArgumentException("salary cannot be negative");
        this.salary = salary;
    }
}

Using the same names for parameters and fields is the standard Java convention, because the parameter name then documents exactly which field it sets. this. resolves the ambiguity.

The silent bug without this

public Employee(String name, double salary) {
    name = name;           // assigns the parameter to itself
    salary = salary;       // same
}

This compiles. Both lines assign each parameter to itself, and the fields remain at their defaults (null and 0.0). The object appears to be created successfully but contains no data. IDEs warn about self-assignment, and declaring fields final turns it into a compile error, because the compiler then notices the final field is never assigned. Both are reasons to make fields final wherever possible.

Calling Another Constructor: this(...)

this(...) with arguments calls another constructor of the same class. It lets several constructors share one implementation:

public class Connection {
    private final String host;
    private final int port;
    private final int timeoutSeconds;

    public Connection(String host, int port, int timeoutSeconds) {
        this.host = host;
        this.port = port;
        this.timeoutSeconds = timeoutSeconds;
    }

    public Connection(String host, int port) {
        this(host, port, 30);          // default timeout
    }

    public Connection(String host) {
        this(host, 443);               // default port
    }
}

new Connection("api.example.com") runs the one-argument constructor, which calls the two-argument one, which calls the three-argument one. Only the last actually assigns fields.

Note the two different uses of the same keyword:

SyntaxMeaning
this.fieldThe current object's field
this.method()Call a method on the current object
this(...)Call another constructor of this class (only inside a constructor)

Constructor chaining is covered in detail in the Constructor Overload lesson.

Passing the Current Object

An object can pass itself to another method or constructor using this:

public class Order {
    private final List<OrderLine> lines = new ArrayList<>();

    public void addLine(String product, int qty) {
        lines.add(new OrderLine(this, product, qty));   // the line knows its order
    }
}

public class OrderLine {
    private final Order order;
    private final String product;
    private final int qty;

    public OrderLine(Order order, String product, int qty) {
        this.order = order;
        this.product = product;
        this.qty = qty;
    }
}

Each OrderLine stores a reference back to the Order that created it. The same technique is used when an object registers itself with something else:

public class TemperatureDisplay implements SensorListener {
    public TemperatureDisplay(Sensor sensor) {
        sensor.addListener(this);       // "notify me when readings change"
    }

    @Override
    public void onReading(double value) {
        System.out.println("Now: " + value);
    }
}

Passing this from inside a constructor (as above) lets other code reach the object before its constructor finishes. If the sensor called onReading immediately, it would run on a partly initialized object. In real code, register listeners after construction, for example in a separate start() method or a factory method.

Returning this for Method Chaining

A method can return this so that calls can be chained:

public class QueryBuilder {
    private String table;
    private final List<String> conditions = new ArrayList<>();
    private int limit = -1;

    public QueryBuilder from(String table) {
        this.table = table;
        return this;
    }

    public QueryBuilder where(String condition) {
        conditions.add(condition);
        return this;
    }

    public QueryBuilder limit(int limit) {
        this.limit = limit;
        return this;
    }

    public String build() {
        StringBuilder sql = new StringBuilder("SELECT * FROM ").append(table);
        if (!conditions.isEmpty()) {
            sql.append(" WHERE ").append(String.join(" AND ", conditions));
        }
        if (limit > 0) {
            sql.append(" LIMIT ").append(limit);
        }
        return sql.toString();
    }
}
String sql = new QueryBuilder()
        .from("students")
        .where("year = 2")
        .where("gpa > 8.0")
        .limit(10)
        .build();

System.out.println(sql);
// SELECT * FROM students WHERE year = 2 AND gpa > 8.0 LIMIT 10

Each method modifies the builder and returns the same object, so the next call operates on it. This is the basis of the builder pattern and of "fluent" APIs. (This example only illustrates chaining; real database code must use PreparedStatement parameters, never strings built from user input, to prevent SQL injection.)

Comparing with this

this can be compared to other references, most commonly as the first check in equals:

@Override
public boolean equals(Object o) {
    if (this == o) return true;                  // same object: equal by definition
    if (!(o instanceof Employee other)) return false;
    return name.equals(other.name) && salary == other.salary;
}

The this == o check is a quick shortcut: an object is always equal to itself, so there is no need to compare fields.

this Is Not Available in Static Code

Static methods belong to the class, not to any object, so there is no current object:

public class Counter {
    private int count;

    public static void reset() {
        this.count = 0;       // compile error: non-static variable this cannot be referenced
                              // from a static context
    }
}

The same applies in main, which is static. This is why early beginner programs fail when main tries to use a field or instance method directly: main has no this.

this in Inner Classes and Lambdas

An inner class (a non-static nested class) has its own this. To reach the enclosing object, qualify it with the outer class name:

public class Course {
    private final String title = "Java Basics";

    class Lesson {
        private final String title;

        Lesson(String title) { this.title = title; }

        String fullTitle() {
            return Course.this.title + " / " + this.title;
        }
    }
}

this.title is the lesson's title; Course.this.title is the enclosing course's.

A lambda does not introduce a new this. Inside a lambda, this means the same object it means in the surrounding method:

public class Timer {
    private final String name = "build-timer";

    public Runnable task() {
        return () -> System.out.println(this.name);   // this is the Timer
    }
}

An anonymous class, by contrast, is a separate object, and this inside it refers to the anonymous class instance. This difference is one reason lambdas are simpler to use for short callbacks.

Summary of Uses

UseExampleWhy
Access a shadowed fieldthis.name = name;Parameter has the same name as the field
Call another constructorthis(host, 443);Share initialization logic
Pass the current objectlist.add(this);Give other code a reference to this object
Return the current objectreturn this;Enable method chaining
Compare with another referenceif (this == o)Identity check, e.g. in equals
Reach the enclosing instanceOuter.this.fieldFrom inside an inner class

Practical Example: Linked Tasks

import java.util.ArrayList;
import java.util.List;

public class Task {
    private final String name;
    private final List<Task> dependsOn = new ArrayList<>();
    private boolean done;

    public Task(String name) {
        this.name = name;
    }

    public Task after(Task other) {
        if (other == this) {
            throw new IllegalArgumentException(name + " cannot depend on itself");
        }
        this.dependsOn.add(other);
        return this;
    }

    public boolean canStart() {
        for (Task t : dependsOn) {
            if (!t.done) return false;
        }
        return true;
    }

    public void complete() {
        if (!this.canStart()) {
            throw new IllegalStateException(name + " is blocked");
        }
        this.done = true;
    }

    @Override
    public String toString() {
        return name + (done ? " ✓" : canStart() ? " (ready)" : " (blocked)");
    }

    public static void main(String[] args) {
        Task design = new Task("Design");
        Task build = new Task("Build").after(design);
        Task test = new Task("Test").after(build);
        Task deploy = new Task("Deploy").after(test).after(build);

        design.complete();
        build.complete();

        System.out.println(List.of(design, build, test, deploy));
    }
}

Output:

[Design ✓, Build ✓, Test (ready), Deploy (blocked)]

The constructor uses this.name to set the field from a same-named parameter. after uses other == this to reject a self-dependency, adds to this.dependsOn, and returns this so dependencies can be chained in one expression, as in the deploy line. Inside canStart, t.done reads the done field of each dependency, while this.done in complete sets the field of the task the method was called on.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about this Keyword and get answers drawn from it.

Signed-in readers only.