🤔불변 객체(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;
}
}
- final 키워드를 사용하여 클래스를 불변으로 만든다.
- Collections.unmodifiableList를 사용하여 생성자에 list가 들어올 때 변경 불가능하게 만든다.
정리
▶ Java에서 final만을 사용해서 불변 객체를 만들 수 없는 경우도 있다. 추가 작업이 필요하다.
▶ 불변 객체를 만들기 위해서는 다음 규칙을 따라야 한다.
- 클래스에 final키워드 사용
- 모든 클래스 변수를 private와 final로 선언
- 객체를 생성하기 위한 생성자 혹은 정적 팩토리 메소드 추가
- 참조에 의해 변경 가능성이 있는 경우 Collections.unmodifiableList와 같은 방어적 복사를 이용하여 전달
Reference : https://mangkyu.tistory.com/131
'Languages > Java' 카테고리의 다른 글
[Java] 멀티스레드 환경에서의 동시성 문제와 대책 (0) | 2023.04.12 |
---|---|
[Java] equals(), hashCode()를 재정의 해야 하는 이유 (0) | 2023.04.12 |
[Java] 자바 Collection 개념 정리 & 예제 (0) | 2023.04.10 |
[Java] 상속과 인터페이스 개념 정리 (0) | 2023.04.10 |
[Java] static, static method 개념 정리 (0) | 2023.04.09 |
댓글