어제 오늘 내일

[Java] Immutable 객체란? 본문

IT/Java

[Java] Immutable 객체란?

hi.anna 2026. 1. 4. 00:53

Java에서 Immutable 객체(불변 객체)
한 번 생성되면 내부 상태가 절대로 변경되지 않는 객체를 말합니다.
즉, 객체의 필드 값을 수정할 수 없으며 오직 읽기(Read)만 가능합니다.

불변 객체는 안전하고 예측 가능한 동작을 제공하기 때문에
멀티스레드 환경, 캐싱, 값 객체(Value Object) 설계에서 매우 유용합니다.

 

1. Immutable 객체의 정의

Immutable 객체는 다음 특징을 만족합니다:

  • 객체 생성 후 상태가 절대 변경되지 않는다.
  • 모든 필드는 final이며, 외부에서 변경할 수 없다.
  • setter 메서드가 존재하지 않는다.
  • 변경이 필요한 경우 새로운 객체를 생성한다.

대표적인 예: String, Integer, LocalDate, LocalTime

 

2. Immutable 객체가 필요한 이유

✔ 1) 예측 가능하고 안전한 동작

객체 상태가 변하지 않으므로 사이드 이펙트 없음.

✔ 2) Thread-safe (멀티스레드 안전)

여러 스레드가 동시에 사용해도 값이 변하지 않으므로 동기화 필요 없음.

✔ 3) 동등성 비교가 쉬움

상태가 변하지 않아 객체 비교 로직이 단순함.

✔ 4) 캐싱과 재사용 가능

변하지 않으므로 한 번 만들어 두면 계속 재사용 가능.

 

3. Immutable 객체 만들기 규칙

Java에서 직접 Immutable 객체를 만들려면 다음 원칙을 따릅니다:

① 멤버 변수는 모두 private final

private final int age;
private final String name;

② 생성자를 통해 한 번만 값 설정

public Person(String name, int age) {
    this.name = name;
    this.age = age;
}

③ setter 메서드 금지

값 변경을 막기 위해 setter는 만들지 않습니다.

④ Mutable 객체는 깊은 복사(deep copy)

List, Date처럼 변경 가능한 객체는 외부에서 수정할 수 없도록 복사해야 합니다.

예:

private final List<String> list;

public Person(List<String> list) {
    this.list = new ArrayList<>(list); // 깊은 복사
}

⑤ 자신을 반환하는 메서드에서도 새로운 객체 생성

public Person withAge(int newAge) {
    return new Person(this.name, newAge);
}

 

 

4. Immutable 객체 실전 예제

public final class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }

    public Person withAge(int newAge) {
        return new Person(this.name, newAge);
    }
}

사용:

Person p1 = new Person("Tom", 20);
Person p2 = p1.withAge(30);

System.out.println(p1.getAge()); // 20
System.out.println(p2.getAge()); // 30

설명

  • p1 객체는 변하지 않음
  • withAge()는 새로운 객체를 반환

 

5. Mutable(변경 가능) 객체와의 차이

구분 Immutable  Mutable
값 변경 불가능 가능
스레드 안전성 높음 낮음
예측 가능성 높음 낮음
메모리 사용 더 많음(새 객체 생성) 적음(재사용 가능)
String, Integer StringBuilder, ArrayList

 

6. Immutable 객체의 대표 예: String

String은 대표적인 불변 객체입니다.

String s = "Hello";
s.toUpperCase(); // "HELLO" 반환하지만 원본은 변경되지 않음

새로운 문자열을 반환할 뿐 기존 값은 변경되지 않습니다.

 

7. 효율적인 Immutable 객체 생성: Lombok @Value

Lombok을 사용하면 불변 객체를 매우 쉽게 만들 수 있습니다.

@Value
public class Person {
    String name;
    int age;
}

자동으로 다음을 생성해 줌:

  • 모든 필드를 private final
  • 생성자
  • getter
  • equals & hashCode

 

8. Immutable 객체의 단점

✔ 값이 바뀔 때마다 새로운 객체 생성 → 메모리 사용 증가

예: String을 반복해서 수정하면 StringBuilder를 쓰는 이유.

✔ 상태 변경이 복잡할 수 있음

with 메서드를 많이 만들어야 할 수 있음.

 

9. 정리

  • Immutable 객체는 생성 후 상태가 변하지 않는 객체
  • 모든 필드는 private final
  • setter 없음
  • 변경 시 새로운 객체 반환
  • Thread-safe하며 안정적인 구조를 제공
  • Java의 String, Integer, LocalDate 등이 대표적인 예

 

 

반응형
Comments