Mutable Object란 객체가 생성된 후 상태가 변경될 수 있는 객체이다. 즉 객체의 필드나 속성 값을 직접 수정할 수 있으며 이러한 변경 사항은 객체의 상태에 반영된다. Java에서 변경 가능한 객체의 예로는 배열, ArrayList 및 HashMap과 같은 컬렉션, 사용자가 생성하는 클래스들이 있다.
Immutable Object는 객체가 생성된 후에는 변경 할 수 없는 객체이다. 불변 객체가 생성되면 상태를 수정할 수 없으며 값을 변경하려고 시도하면 새 객체가 생성된다. Java의 불변 객체 예로는 String과 Integer, Double과 같은 Wrapper Class가 있다.
자바에서 final 키워드를 변수에 사용하면 해당 변수의 참조 주소는 변경될 수 없음을 뜻한다. 불변 객체는 재할당은 가능하지만, 한 번 할당하면 내부 데이터를 변경할 수 없는 객체를 뜻하기 때문에 final을 사용한다고 불변 객체가 되는 것은 아니다.
방어적 복사는 생성자의 인자로 받은 객체의 복사본을 만들어 내부 필드를 초기화하거나, getter메서드에서 내부의 객체를 반환할 때, 객체의 복사본을 만들어 반환하는 것.
깊은 복사는 객체를 복사 할 때, 해당 객체와 인스턴스 변수까지 복사하는 방식. 전부를 복사하여 새 주소에 담기 때문에 참조를 공유하지 않는다. 깊은복사를 하기 위해서 객체는 Cloneable Interface를 Implement 해야하고 clone 메서드를 오버라이드해야한다.
Unmodifiable과 Immutable은 다르다. Unmodifiable이라는 키워드가 불변을 보장해주지는 않는다.
방어적 복사는 참조를 끊는 행위이지만, Unmodifiable은 참조를 끊지 않고 단순히 특정 리스트에서 요소의 변경이 일어날 경우 예외를 던진다. 그래서 생성자 단계에서 방어적 복사를 취하지 않고, getter에서 Unmodifiable만 취할 경우 초기 생성자로 주입한 컬렉션의 변화가 생기면 불변성이 깨진다.
내부에 저장하는 객체들의 불변성까지도 달성하고 싶다면, 해당 객체를 불변 객체로 선언하던지 방어적 복사본을 활용하자.
방어적 복사를 통해 객체의 복사본을 만들었어도 내부 요소들이 mutable하다면 해당 객체는 immutable할 수 없다.
객체를 immutable로 만들기 위해서는 방어적 복사 외에도 객체 내부의 요소들까지 모두 immutable로 만들어주어야 한다.
https://datatrained.com/post/mutable-and-immutable-objects-in-java/