본문 바로가기
Languages/Java

[Java] 불변 객체(Immutable Object)란 무엇인가?

by 젊은오리 2023. 4. 9.
728x90

🤔불변 객체(immutable object)란?

불변 객체란 객체 생성 이후 내부의 상태가 변하지 않는 객체를 말한다.

즉, 한 번 생성된 불변 객체의 상태는 그 이후에 변경할 수 없다.

Java의 대표적인 불변 객체로는 String이 있다. 다음과 같이 str를 String으로 선언해보자.

 

그럼 다음과 같이 문자열을 추가하면 어떻게 될까?

str이 변경됐다고 생각할 수 있겠지만, 사실 “aa”라는 String 객체는 그대로 남아 있고, “aabb”라는 새로운 객체가 str에 할당된다. 즉, String은 불변 객체이다.

 

😄불변 객체 사용 시 장점은 무엇인가?

1. Thread-Safe하다.

- 공유 자원이 불변이라면, 항상 동일한 값을 반환하기 때문에 더 이상 동기화를 고려하지 않아도 될 것이다. 따라서 스레드 안정성이 보장된다.

2. 사용성이 높아진다.

- 불변 객체는 객체 지향 프로그래밍에서 중요한 개념 중 하나인 "캡슐화(encapsulation)"를 보다 잘 지원한다. 객체의 내부 상태를 외부에서 변경할 수 없으므로, 객체의 사용성이 높아지고, 객체 간의 의존성이 감소한다.

3. 다른 사람이 작성한 함수를 예측 가능하며 안전하게 사용할 수 있다.

- 협업 시에 불변성이 보장된 함수라면 다른 사람이 개발한 함수를 위험 없이 이용할 수 있다. 마찬가지로 다른 사람도 내가 작성한 메소드를 호출하여도, 값이 변하지 않음을 보장 받을 수 있다. 그렇기 때문에 우리는 변경에 대한  불안 없이 다른 사람의 코드를 이용할 수 있다.

 

🤔final을 붙여서 불변 객체를 만들 수 있을까?

final 키워드는 변수의 값이 변경되지 않음을 보장해주는 것이지, 객체의 내부 상태가 변경되지 않음을 보장해주는 것은 아니다. 즉, final 키워드를 사용해서 객체를 만들더라도, 객체 내부의 상태가 변경될 수 있다.

예시로 아래 ImmutableClass 클래스를 보자.

다음 클래스는 List<String>형의 list를 final변수로 갖고 있다.

public class ImmutableClass {
    private final List<String> list;

    public ImmutableClass(List<String> list) {
        this.list = list;
    }

    public List<String> getList() {
        return list;
    }
}

 

아래와 같이 main클래스에서 Lion이란 list를 선언 후, 이 list를 변수로 갖는 ImmutableClass 객체를 생성했다. 이후, list객체에 “Tiger”를 추가하면, ImmutableClass 객체가 가리키는 리스트 내부의 상태가 변경되고, 이를 출력 시 [Lion, Tiger]의 리스트가 출력된다.

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Lion");
        ImmutableClass obj = new ImmutableClass(list);

        System.out.println(obj.getList()); // [Lion]

        list.add("Tiger");
        System.out.println(obj.getList()); // [Lion, Tiger]
    }
}

즉, 참조 타입인 경우 final이 붙었어도 불변 객체를 만들지 못하는 경우가 발생한다.

 

따라서 final키워드가 붙은 필드가 참조 타입인 경우에도 내부 상태를 변경할 수 없도록 하려면 ImmutableClass를 다음과 같이 구현해야 한다.

public final class ImmutableClass { //class에 final키워드 사용
    private final List<String> list;

    public ImmutableClass(List<String> list) { //변경 후 저장
        this.list = Collections.unmodifiableList(new ArrayList<>(list));
    }

    public List<String> getList() {
        return list;
    }
}
  1. final 키워드를 사용하여 클래스를 불변으로 만든다.
  2. Collections.unmodifiableList를 사용하여 생성자에 list가 들어올 때 변경 불가능하게 만든다.

 

정리

▶ Java에서 final만을 사용해서 불변 객체를 만들 수 없는 경우도 있다. 추가 작업이 필요하다.

▶ 불변 객체를 만들기 위해서는 다음 규칙을 따라야 한다.

  1. 클래스에 final키워드 사용
  2. 모든 클래스 변수를 private와 final로 선언
  3. 객체를 생성하기 위한 생성자 혹은 정적 팩토리 메소드 추가
  4. 참조에 의해 변경 가능성이 있는 경우 Collections.unmodifiableList와 같은 방어적 복사를 이용하여 전달

 

Reference : https://mangkyu.tistory.com/131

728x90

댓글