본문으로 건너뛰기

6.5 this 키워드와 this() (The 'this' Keyword)

객체지향 프로그래밍에서 생성자나 메서드의 매개변수 이름이 클래스의 멤버 변수 이름과 같은 경우가 매우 자주 발생합니다. 이런 상황에서 '어떤 것이 현재 인스턴스의 변수인지'를 명확히 구분하기 위해 자바는 this 키워드를 제공합니다.

1. this 키워드란?

this현재 객체(인스턴스) 자신을 가리키는 참조 변수 입니다.

  • 인스턴스가 생성될 때 JVM이 자동으로 this를 해당 인스턴스의 주소로 설정합니다.
  • 모든 인스턴스 메서드와 생성자 내부에서 숨겨진 채로 존재합니다.
  • static 컨텍스트(클래스 메서드)에서는 사용할 수 없습니다.

2. this의 3가지 사용법

사용법 1: this.필드명 — 필드와 매개변수 구분

가장 흔한 사용법입니다. 매개변수 이름과 인스턴스 변수 이름이 같을 때 구분합니다.

public class Car {
String brand; // 인스턴스 변수
String color;
int speed;

// 매개변수 이름과 인스턴스 변수 이름이 동일
Car(String brand, String color, int speed) {
// this.brand = 인스턴스 변수 brand
// brand = 매개변수 brand
this.brand = brand;
this.color = color;
this.speed = speed;
}

void setSpeed(int speed) {
// this 없이 그냥 speed = speed; 를 쓰면
// 둘 다 지역 변수(매개변수)로 취급되어 인스턴스 변수에 저장 안 됨!
this.speed = speed;
}
}
this 없이 쓰면 어떻게 될까?
void setSpeed(int speed) {
speed = speed; // 매개변수에 매개변수를 대입 → 아무 의미 없음!
// 인스턴스 변수 speed는 여전히 0
}

이름이 같으면 항상 가장 가까운 스코프의 변수(매개변수)가 우선됩니다. this.를 붙여야 인스턴스 변수에 접근할 수 있습니다.

사용법 2: this() — 같은 클래스의 다른 생성자 호출

this()는 같은 클래스 내의 다른 생성자를 호출할 때 사용합니다.

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

// 기본 생성자: 모든 기본값을 가진 생성자에 위임
Car() {
this("현대", "흰색", "자동", 4); // 반드시 첫 줄!
}

Car(String brand) {
this(brand, "흰색", "자동", 4);
}

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

// 핵심 생성자: 실제 초기화를 담당
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 + "도어";
}
}

public class CarTest {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car("기아");
Car c3 = new Car("BMW", "검정");
Car c4 = new Car("벤츠", "은색", "수동", 2);

System.out.println(c1); // 현대 흰색 자동 4도어
System.out.println(c2); // 기아 흰색 자동 4도어
System.out.println(c3); // BMW 검정 자동 4도어
System.out.println(c4); // 벤츠 은색 수동 2도어
}
}
this() 규칙
  1. 반드시 생성자의 첫 번째 줄 에 작성해야 합니다.
  2. 메서드가 아닌 생성자 내부 에서만 사용 가능합니다.
  3. 순환 호출이 되면 안 됩니다 (A() → B() → A() 금지).

사용법 3: return this — 메서드 체이닝 패턴

메서드가 this를 반환하면, 여러 메서드 호출을 한 줄에 연결 할 수 있습니다.

public class StringBuilder2 {
private String content = "";

public StringBuilder2 append(String text) {
content += text;
return this; // 자기 자신을 반환 → 메서드 체이닝 가능
}

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) {
// return this 덕분에 . 으로 연결 가능
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. static 컨텍스트에서 this 사용 불가

static 메서드는 인스턴스가 없는 상태에서도 호출될 수 있습니다. 따라서 '현재 인스턴스'를 가리키는 this를 사용할 수 없습니다.

public class StaticThisExample {
String name = "홍길동";

// 인스턴스 메서드: this 사용 가능
void instanceMethod() {
System.out.println(this.name); // 정상
}

// static 메서드: this 사용 불가
static void staticMethod() {
// System.out.println(this.name); // 컴파일 에러!
// "Cannot use 'this' in a static context"
}
}
왜 static에서 this를 못 쓸까?

static 멤버는 클래스 수준에서 존재하며, 특정 인스턴스와 무관합니다. 예를 들어 Car.staticMethod()를 호출할 때 Car 객체가 없을 수도 있으므로, this가 가리킬 인스턴스가 존재하지 않을 수 있습니다.

4. 메서드 체이닝 패턴 완전 구현

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) {
// 메서드 체이닝으로 SQL 쿼리를 직관적으로 작성
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. 빌더 패턴에서의 this 활용

생성자에서 다룬 빌더 패턴의 내부 빌더 클래스에서 this가 메서드 체이닝의 핵심입니다.

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 = "씬";
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; // this 반환 → 체이닝
}

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', 치즈=%b, 페퍼로니=%b, 버섯=%b}",
size, crust, cheese, pepperoni, mushroom);
}
}

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

Pizza special = new Pizza.Builder("미디엄")
.crust("치즈크러스트")
.cheese(true)
.pepperoni(true)
.mushroom(true)
.build();

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

출력:

Pizza{size='라지', crust='씬', 치즈=true, 페퍼로니=false, 버섯=false}
Pizza{size='미디엄', crust='치즈크러스트', 치즈=true, 페퍼로니=true, 버섯=true}

6. 고급 팁: this를 매개변수로 전달

현재 객체 자신을 다른 메서드에 인수로 전달할 때도 this를 사용합니다.

public class EventListener {
void onEvent(Button source) {
System.out.println("버튼 클릭됨: " + source.label);
}
}

public class Button {
String label;
EventListener listener;

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

void click() {
// 자기 자신(this)을 이벤트 리스너에게 전달
listener.onEvent(this);
}
}

public class EventTest {
public static void main(String[] args) {
EventListener listener = new EventListener();
Button btn = new Button("확인", listener);
btn.click(); // 출력: 버튼 클릭됨: 확인
}
}

요약

사용법문법목적
필드 접근this.필드명매개변수와 인스턴스 변수 이름 구분
생성자 호출this(인수...)같은 클래스의 다른 생성자 호출 (코드 중복 제거)
자기 자신 반환return this메서드 체이닝 패턴 구현
자기 자신 전달method(this)현재 객체를 다른 메서드의 인수로 전달
핵심 요약
  • this: 현재 인스턴스를 가리키는 참조 변수
  • this(): 같은 클래스의 다른 생성자를 호출 (반드시 생성자 첫 줄)
  • static 메서드에서는 this 사용 불가
  • return this로 메서드 체이닝 패턴 구현