Post

[JAVA] 불변 객체

[JAVA] 불변 객체

자바 데이터 타입 분류

  • 기본형(Primitive Type): 값을 직접 저장. 공유 X
  • 참조형(Reference Type): 객체의 참조값을 저장. 공유 O

기본형은 값 복사

1
2
3
4
int a = 10;
int b = a;
b = 20;
System.out.println(a); // 10
  • b = a 는 값을 복사함 → ab 는 완전히 별개

참조형은 참조값 복사 (공유 발생)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//참조형 변수는 하나의 인스턴스를 공유한다.
//즉, 참조형 변수는 같은 참조값(x001)을 통해 같은 인스턴스를 참조
Address a = new Address("서울"); //새로운 객체 참조
Address b = a;  //참조값(x001) 복사해 전달 (참조값의 공유를 막을 방법 X)

System.out.println("a = " + a);
System.out.println("b = " + b);

System.out.println("b 를 부산으로 변경");
b.setValue("부산");
System.out.println("a = " + a); //사이드 이펙트 발생 -> 특정부분 변경이 예기치 않게 다른 부분에 영향을 줌 (나는 b만 바꾸고 싶었는데?)
System.out.println("b = " + b);

//참조형 변수는 참조값을 통해 같은 객체(인스턴스)를 공유
  • ab 가 같은 객체를 참조 → 하나 변경 시 사이드 이펙트 발생

사이드 이펙트란?

  • 의도하지 않은 값 변경 효과
  • b만 바꾸려 했는데 a도 바뀜 → 디버깅 어려움

해결 1: 객체 공유 안 하기

1
2
3
Address a = new Address("서울");
Address b = new Address("서울");
//a와 b가 서로다른 인스턴스 참조
  • 완전히 다른 객체 → 공유 안 됨
  • 하지만 공유 방지 강제할 방법 없음

객체 공유를 막을 수 없는 이유

1
2
Address a = new Address("서울");
Address b = a; // 정상 문법, 막을 방법 없음
  • 참조값은 언제든 다른 변수에 복사 가능
  • 공유 자체는 막을 수 없음 → “값 변경”을 막는 게 핵심

해결 2: 불변 객체로 설계

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//불변 객체 예제 (불변 클래스)
public class ImmutableAddress {
  private final String value; //final로 선언해 내부 값 변경 불가능

  public ImmutableAddress(String value) {
    this.value = value;
  }

  public String getValue() {
    return value;
  }

  @Override
  public String toString() {
    return "ImmutableAddress{" +
      "value='" + value + '\'' +
      '}';
  }
}

  • 값 변경 메서드 제거 (setValue() 없음)
  • value 필드는 final
  • 변경이 필요하면 새 객체 생성

불변 객체 사용 시

1
2
3
4
5
6
7
8
9
10
11
12
13
ImmutableAddress a = new ImmutableAddress("서울");
ImmutableAddress b = a; //참조값 대입을 막을 수 없다
System.out.println("a = " + a);
System.out.println("b = " + b);

System.out.println("b -> 부산");
//b.setValue("부산"); //컴파일 오류 발생 setValue 없어 변경 불가
b = new ImmutableAddress("부산"); //신규 생성
System.out.println("a = " + a);
System.out.println("b = " + b);

//final로 단순한 제약을 만들어 사이드 이펙트라는 큰 문제를 막음
//불변객체의 값을 변경하고 싶으면 새로운 불변객체 생성
  • 공유는 되지만 값은 절대 안 바뀜
  • 사이드 이펙트 완전 차단

가변 객체 vs 불변 객체

구분 가변 객체 (Address) 불변 객체 (ImmutableAddress)
값 변경 가능 ✅ setValue() 있음 ❌ 없음
사이드 이펙트 발생 가능성 높음 없음
공유 참조 안전성 낮음 높음

불변 객체 활용 예

1
2
3
4
//불변 객체는 값을 변경하면 안됨, 기존 값에 새로운 값을 더해야 함
public ImmutableObj add(int addValue) {
  return new ImmutableObj(value + addValue);  //객체는 기존값을 변경하지 않고 계산값을 새로운 객체로 만들어 반환
}
  • 기존 객체는 유지
  • 새 객체에 결과 저장 → 함수형 스타일

  • 참조형은 공유되기 때문에 사이드 이펙트 주의
  • 불변 객체는 공유돼도 안전 → 값을 변경할 수 없기 때문
  • 자바 기본 클래스(StringIntegerLocalDate) 대부분 불변 객체
  • 불변 객체는 안정성, 멀티스레드, 캐시, 값 타입 등에서 유용

출처: 김영한의 실전 자바 - 중급 1편

This post is licensed under CC BY 4.0 by the author.