Skip to main content

6.5 The this Keyword and this()

In object-oriented programming, it is very common for the names of constructor or method parameters to match the names of the class's member variables. In such situations, Java provides the this keyword to clearly distinguish "which one refers to the current instance's variable".

1. What Is the this Keyword?

this is a reference variable that points to the current object (instance) itself.

  • The JVM automatically sets this to the address of the current instance when the instance is created.
  • It exists hidden inside every instance method and constructor.
  • It cannot be used in a static context (class method).

2. Three Uses of this

Use 1: this.fieldName — Distinguishing Fields from Parameters

The most common use. Used when a parameter name is the same as an instance variable name.

public class Car {
String brand; // instance variable
String color;
int speed;

// Parameter names match instance variable names
Car(String brand, String color, int speed) {
// this.brand = instance variable brand
// brand = parameter brand
this.brand = brand;
this.color = color;
this.speed = speed;
}

void setSpeed(int speed) {
// Writing just speed = speed; without this
// treats both as the local variable (parameter) -> nothing stored in instance variable!
this.speed = speed;
}
}
What Happens Without this?
void setSpeed(int speed) {
speed = speed; // assigning parameter to parameter -> meaningless!
// the instance variable speed remains 0
}

When names conflict, the variable in the closest scope(the parameter) takes precedence. You must add this. to access the instance variable.

Use 2: this() — Calling Another Constructor in the Same Class

this() is used to call a different constructor within the same class.

public class Car {
String brand;
String color;
String gearType;
int door;

// Default constructor: delegates to the constructor with all defaults
Car() {
this("Hyundai", "White", "Automatic", 4); // must be on the first line!
}

Car(String brand) {
this(brand, "White", "Automatic", 4);
}

Car(String brand, String color) {
this(brand, color, "Automatic", 4);
}

// Core constructor: handles the actual initialization
Car(String brand, String color, String gearType, int door) {
this.brand = brand;
this.color = color;
this.gearType = gearType;
this.door = door;
}

@Override
public String toString() {
return brand + " " + color + " " + gearType + " " + door + "-door";
}
}

public class CarTest {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car("Kia");
Car c3 = new Car("BMW", "Black");
Car c4 = new Car("Mercedes", "Silver", "Manual", 2);

System.out.println(c1); // Hyundai White Automatic 4-door
System.out.println(c2); // Kia White Automatic 4-door
System.out.println(c3); // BMW Black Automatic 4-door
System.out.println(c4); // Mercedes Silver Manual 2-door
}
}
Rules for this()
  1. Must be written as the first line of a constructor.
  2. Can only be used inside a constructor, not a method.
  3. Circular calls are not allowed (A() -> B() -> A() is forbidden).

Use 3: return this — Method Chaining Pattern

When a method returns this, multiple method calls can be chained on one line.

public class StringBuilder2 {
private String content = "";

public StringBuilder2 append(String text) {
content += text;
return this; // returns itself -> enables method chaining
}

public StringBuilder2 appendLine(String text) {
content += text + "\n";
return this;
}

public StringBuilder2 toUpperCase() {
content = content.toUpperCase();
return this;
}

public String build() {
return content;
}
}

public class MethodChainingTest {
public static void main(String[] args) {
// Because of return this, methods can be chained with .
String result = new StringBuilder2()
.append("Hello, ")
.append("World!")
.appendLine("")
.append("Java is ")
.append("awesome!")
.build();

System.out.println(result);
// Hello, World!
// Java is awesome!
}
}

3. this Cannot Be Used in a Static Context

A static method can be called without an instance. Therefore, this, which refers to "the current instance", cannot be used.

public class StaticThisExample {
String name = "Hong Gildong";

// Instance method: this can be used
void instanceMethod() {
System.out.println(this.name); // works fine
}

// Static method: this cannot be used
static void staticMethod() {
// System.out.println(this.name); // Compile error!
// "Cannot use 'this' in a static context"
}
}
Why Can't static Use this?

static members exist at the class level and are unrelated to any specific instance. For example, when calling Car.staticMethod(), there may be no Car object at all, so there is no instance for this to point to.

4. Full Method Chaining Pattern Implementation

public class QueryBuilder {
private String table = "";
private String select = "*";
private String where = "";
private String orderBy = "";
private int limit = 0;

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

public QueryBuilder select(String columns) {
this.select = columns;
return this;
}

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

public QueryBuilder orderBy(String column) {
this.orderBy = column;
return this;
}

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

public String build() {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(select);
sql.append(" FROM ").append(table);
if (!where.isEmpty()) {
sql.append(" WHERE ").append(where);
}
if (!orderBy.isEmpty()) {
sql.append(" ORDER BY ").append(orderBy);
}
if (limit > 0) {
sql.append(" LIMIT ").append(limit);
}
return sql.toString();
}
}

public class QueryBuilderTest {
public static void main(String[] args) {
// Write SQL queries intuitively with method chaining
String query1 = new QueryBuilder()
.from("users")
.select("id, name, email")
.where("age >= 20")
.orderBy("name")
.limit(10)
.build();

String query2 = new QueryBuilder()
.from("orders")
.select("*")
.where("status = 'pending'")
.build();

System.out.println(query1);
// SELECT id, name, email FROM users WHERE age >= 20 ORDER BY name LIMIT 10

System.out.println(query2);
// SELECT * FROM orders WHERE status = 'pending'
}
}

5. Using this in the Builder Pattern

In the inner Builder class from the constructor section, this is the key to method chaining.

public class Pizza {
private final String size;
private final String crust;
private final boolean cheese;
private final boolean pepperoni;
private final boolean mushroom;

private Pizza(Builder builder) {
this.size = builder.size;
this.crust = builder.crust;
this.cheese = builder.cheese;
this.pepperoni = builder.pepperoni;
this.mushroom = builder.mushroom;
}

public static class Builder {
private final String size;
private String crust = "Thin";
private boolean cheese = true;
private boolean pepperoni = false;
private boolean mushroom = false;

public Builder(String size) {
this.size = size;
}

public Builder crust(String crust) {
this.crust = crust;
return this; // return this -> chaining
}

public Builder cheese(boolean cheese) {
this.cheese = cheese;
return this;
}

public Builder pepperoni(boolean pepperoni) {
this.pepperoni = pepperoni;
return this;
}

public Builder mushroom(boolean mushroom) {
this.mushroom = mushroom;
return this;
}

public Pizza build() {
return new Pizza(this);
}
}

@Override
public String toString() {
return String.format("Pizza{size='%s', crust='%s', cheese=%b, pepperoni=%b, mushroom=%b}",
size, crust, cheese, pepperoni, mushroom);
}
}

public class PizzaTest {
public static void main(String[] args) {
Pizza margherita = new Pizza.Builder("Large")
.crust("Thin")
.cheese(true)
.build();

Pizza special = new Pizza.Builder("Medium")
.crust("Cheese Crust")
.cheese(true)
.pepperoni(true)
.mushroom(true)
.build();

System.out.println(margherita);
System.out.println(special);
}
}

Output:

Pizza{size='Large', crust='Thin', cheese=true, pepperoni=false, mushroom=false}
Pizza{size='Medium', crust='Cheese Crust', cheese=true, pepperoni=true, mushroom=true}

6. Advanced Tip: Passing this as a Parameter

this can also be used to pass the current object as an argument to another method.

public class EventListener {
void onEvent(Button source) {
System.out.println("Button clicked: " + source.label);
}
}

public class Button {
String label;
EventListener listener;

Button(String label, EventListener listener) {
this.label = label;
this.listener = listener;
}

void click() {
// Pass the current object (this) to the event listener
listener.onEvent(this);
}
}

public class EventTest {
public static void main(String[] args) {
EventListener listener = new EventListener();
Button btn = new Button("OK", listener);
btn.click(); // Output: Button clicked: OK
}
}

Summary

UseSyntaxPurpose
Field accessthis.fieldNameDistinguish instance variable from parameter
Constructor callthis(args...)Call another constructor in the same class (remove code duplication)
Return selfreturn thisImplement method chaining pattern
Pass selfmethod(this)Pass the current object as an argument to another method
Key Summary
  • this: a reference variable pointing to the current instance
  • this(): calls another constructor in the same class (must be on the first line of the constructor)
  • this cannot be used in static methods
  • Use return this to implement method chaining