Java Mutable, Immutable

ahnjs·2023년 6월 16일
post-thumbnail

Mutable과 Immutable

Mutable Object란 객체가 생성된 후 상태가 변경될 수 있는 객체이다. 즉 객체의 필드나 속성 값을 직접 수정할 수 있으며 이러한 변경 사항은 객체의 상태에 반영된다. Java에서 변경 가능한 객체의 예로는 배열, ArrayList 및 HashMap과 같은 컬렉션, 사용자가 생성하는 클래스들이 있다.

Immutable Object는 객체가 생성된 후에는 변경 할 수 없는 객체이다. 불변 객체가 생성되면 상태를 수정할 수 없으며 값을 변경하려고 시도하면 새 객체가 생성된다. Java의 불변 객체 예로는 String과 Integer, Double과 같은 Wrapper Class가 있다.

장단점

Mutable Object

장점

  • 가변 객체는 상태 변경을 허용하므로 동적 상황에 유연하게 적응할 수 있다.
  • 상태가 수정될 때 새 객체를 생성할 필요가 없기 때문에 대량의 데이터를 처리할 때 불변 객체보다 더 효율적일 수 있다.
  • 특정 상황에서 메모리 사용량을 줄이고 성능을 향상시킬 수 있다.

단점

  • 가변 객체는 본질적으로 스레드로부터 안전하지 않으며 동시 프로그래밍에서 올바르게 사용되도록 특별한 주의가 필요
  • 생성 후에 수정될 수 있어 의도하지 않은 변경이 발생할 수 있다.
  • 특히 대규모 코드베이스에서는 추론하고 디버깅하기 더 어려울 수 있다.

Immutable Object

장점

  • 불변 객체는 본질적으로 스레드로부터 안전하며 동기화할 필요 없이 여러 스레드 간에 안전하게 공유될 수 있다.
  • 생성 후에는 상태를 수정할 수 없어 의도하지 않은 변경의 위험이 줄어들기 때문에 변경 가능한 객체보다 더 안전하다.
  • 동작이 더 예측 가능하기 때문에 추론하고 디버깅하기 더 쉽다.

단점

  • 불변 객체는 생성 후에 상태를 변경할 수 없기 때문에 가변 객체보다 유연성이 떨어진다.
  • 상태가 수정되면 새 객체를 생성해야 하므로 대량의 데이터를 처리할 때 변경 가능한 객체보다 효율성이 떨어질 수 있다.
  • 상태를 수정할 때마다 새 개체가 생성되므로 더 많은 메모리가 필요할 수 있다.

Java에서 불변 객체를 생성하는 방법

final이면 Immutable인가?

자바에서 final 키워드를 변수에 사용하면 해당 변수의 참조 주소는 변경될 수 없음을 뜻한다. 불변 객체는 재할당은 가능하지만, 한 번 할당하면 내부 데이터를 변경할 수 없는 객체를 뜻하기 때문에 final을 사용한다고 불변 객체가 되는 것은 아니다.

방어적 복사 vs 깊은 복사

방어적 복사는 생성자의 인자로 받은 객체의 복사본을 만들어 내부 필드를 초기화하거나, getter메서드에서 내부의 객체를 반환할 때, 객체의 복사본을 만들어 반환하는 것.

깊은 복사는 객체를 복사 할 때, 해당 객체와 인스턴스 변수까지 복사하는 방식. 전부를 복사하여 새 주소에 담기 때문에 참조를 공유하지 않는다. 깊은복사를 하기 위해서 객체는 Cloneable Interface를 Implement 해야하고 clone 메서드를 오버라이드해야한다.

Unmodifiable 과 Immutable은 다르다.

Unmodifiable과 Immutable은 다르다. Unmodifiable이라는 키워드가 불변을 보장해주지는 않는다.
방어적 복사는 참조를 끊는 행위이지만, Unmodifiable은 참조를 끊지 않고 단순히 특정 리스트에서 요소의 변경이 일어날 경우 예외를 던진다. 그래서 생성자 단계에서 방어적 복사를 취하지 않고, getter에서 Unmodifiable만 취할 경우 초기 생성자로 주입한 컬렉션의 변화가 생기면 불변성이 깨진다.
내부에 저장하는 객체들의 불변성까지도 달성하고 싶다면, 해당 객체를 불변 객체로 선언하던지 방어적 복사본을 활용하자.

불변 객체 생성하는 방법

  1. 클래스를 final로 선언
  2. 모든 클래스 변수를 private와 final로 선언
  3. 객체를 생성하기 위한 생성자 또는 정적 팩토리 메소드를 추가
  4. 참조에 의해 변경 가능성이 있는 경우 방어적 복사를 이용하여 초기화하거나 전달
    • 필드에 참조 타입이 있을 경우, 해당 객체도 불변성을 보장해야 한다.
    • 필드에 컬렉션이 존재할 경우, 생성자의 인자로 객체를 받았을 때는 방어적 복사를 getter를 통해 객체를 리턴할 때는 방어적 복사 또는 unmodifiableList 반환 중 선택

방어적 복사를 통해 객체의 복사본을 만들었어도 내부 요소들이 mutable하다면 해당 객체는 immutable할 수 없다.
객체를 immutable로 만들기 위해서는 방어적 복사 외에도 객체 내부의 요소들까지 모두 immutable로 만들어주어야 한다.


https://datatrained.com/post/mutable-and-immutable-objects-in-java/

0개의 댓글