불변 객체는 객체 생성 이후 재할당은 가능하지만 내부 상태가 변하지 않는, 변경할 수 없는 객체이다.
String
, Integer
, Boolean
등이 있다.
String str = "a";
str = "ab"
이런 식으로 사용하면 '객체의 모양이 바뀌는 것이니 불변성이 아닌 것 아니냐?' 생각할 수 있는데
이것은 str이 처음 참조하고 있는 "a"의 객체를 "ab"로 바꾸는 것이 아닌 "ab"라는 새로운 객체를 만들고 이 객체를 str이 참조하게 만드는 것이다.
재할당을 한 것이고, 내부 상태를 바꾼 것이 아니라는 것이다.
불변 객체를 만드는 코드이다.
public final class Person {
private final String name;
private final int age;
// 생성자에서 필드 초기화
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getter 메서드만 제공 (Setter 없음)
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
멀티 스레드에서 주로 발생하는 공유 자원에 대해 서로 변경을 하다보니 값이 덮어씌워지는 문제가 있다.
하지만 불변 객체는 항상 동일한 값을 보장하기 때문에 동기화 신경 안 써도 된다.
위 세 개는 내부 요소가 변경되면 갱신 작업이 꼭 필요하지만, 불변 객체의 경우 저장 이후 부가적인 작업이 필요 없다.
가변 객체는 값을 변경하는 set 메소드가 있다면 객체의 값을 항상 파악해야 하고, 이 파악하는 것도 어렵다.
하지만 불변 객체는 값 변경 걱정이 없기 때문에 객체의 신뢰성이 높다.
불변 객체의 경우 상태 변경이 필요 하면 또 새로운 객체를 만들어서 참조를 바꿔주어야 한다.
객체가 계속 늘어난다.
이 부분에서 성능이 떨어지는가? 오라클에서는 아니라고 답했다.
'객체 생성하는 비용이 과대평가되고 있고, 불변 객체를 이용하는 이점이 그 비용을 충분히 상쇄할 수 있다'
정리하자면,
불변 객체를 사용하면 가변 객체보다 생성 비용이 더 들지만
가비지 컬렉션의 스캔 범위와 빈도가 줄어든다
이것이 더 큰 효율을 가져오기 때문에 성능 상 유리하다.