Search
〰️

Mutable과 Immutable

Mutable과 Immutable

Mutable과 Immutable 비교

Mutable
Immutable
생성된 이후 수정 가능
생성된 이후 수정 불가능
이미 존재하는 객체에 재할당 (값 변경)
이미 존재하는 객체이더라도 새로운 객체를 생성하여 재할당
값을 변경할 수 있는 메소드 제공
값을 변경할 수 있는 메소드 제공하지 않음
Mutable class일 경우 Getter와 Setter 존재
Immutable class일 경우 Getter와 setter 미존재
thread safe하지 않을 수 있음 (병렬 처리 시 값을 보장할 수 없게 됨)
thread safe (병렬처리 시 문제 없음)
StringBuffer, StringBuilder, java.util.Date
Legacy classes, Wrapper classes, String class 등
Mutable은 객체의 수정을 허용하나, Immutable인 경우 객체의 수정을 허용하지 않는다.
수정이 필요할 경우 Mutable 객체는 기존의 객체에 수정사항을 곧바로 반영한다.
Immutable 객체의 경우 기존의 객체는 그대로 두고 수정사항을 반영한 새로운 객체를 생성한다.
Immutable의 대표적 예시로는 String class가 존재한다.

Mutable 속성 확인

public class Mutable { public static void main(String[] args) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("abc"); System.out.println(stringBuilder); System.out.println(System.identityHashCode(stringBuilder)); stringBuilder.append("def"); System.out.println(stringBuilder); System.out.println(System.identityHashCode(stringBuilder)); } }
Java
복사
System.identityHashCode(Object) 코드를 통해 String 객체의 메모리 주소값을 함께 출력하였다. 실행 결과는 아래와 같다.
같은 stringBuffer에 할당되었고 stringBuilder의 값을 abc에서 abcdef로 변경하였을 때, 메모리 주소 값이 변경되지 않았다. 이는 곧 1785210046의 메모리 주소에 할당된 abc란 값이 abcdef로 변한 것임을 나타낸다. 따라서 StringBuffer class는 Mutable하게 동작한다.

Immutable 속성 확인

public class Immutable { public static void main(String[] args) { String str = "abc"; System.out.println(str); System.out.println(System.identityHashCode(str)); str += "def"; System.out.println(str); System.out.println(System.identityHashCode(str)); } }
Java
복사
마찬가지로 System.identityHashCode(Object) 코드를 통해 String 객체의 메모리 주소값을 함께 출력하였다. 실행 결과는 아래와 같다.
같은 str 변수에 할당되었지만 str의 값을 abc에서 abcdef로 변경하였을 때, 메모리 주소 값도 같이 변경되었다.
이는 곧 1785210046의 메모리 주소에 할당된 abc란 값이 abcdef로 변한 것이 아니라 1151020327의 메모리 주소에 abcdef란 값을 가진 String 객체가 새로 생성된 것임을 나타낸다.
String class는 Immutable하게 동작한다.

Mutable한 객체를 Immutable한 객체로 사용하기

방어적 복사(defensive copy)

mutable 객체는 생성 이후 값 변경이 자유롭게 가능하여 개발자가 의도하지 않은 객체의 변경이 일어날 수 있다는 단점이 존재한다.
단점의 주 원인은 "레퍼런스를 참조한 다른 객체에서 객체를 변경"하기 때문이다. 이를 해결하고자 객체의 변경이 필요할 경우 참조가 아닌 객체의 방어적 복사(defensive copy)를 통해 새로운 객체를 생성한 후 변경하도록 한다.
적시에 방어적 복사본을 만들라 파트 참고

Setter 메소드 제거

mutable 객체와 immutable 객체의 가장 큰 차이는 생성된 이후 수정이 가능한가, 가능하지 않은가에 있다.
따라서 mutable 객체를 immutable하게 사용하려면 생성된 이후 변경이 불가능하게 만들어주면 된다.
class 객체 생성 이후 값을 변경하는 역할은 setter 메소드가 맡고 있으므로 이를 제거하여 변경을 막는다. 마치 '읽기 전용'으로 파일을 여는 것과 비슷하다.

그 외

final 키워드를 사용한다.
final class는 상속이 불가하며 final 메소드는 오버라이딩이 불가하다. 원치않는 class와 메소드 내의 수정을 막을 수 있다.
모든 클래스 변수를 private과 final로 선언한다.
setter 메소드가 없을 경우 외부에서 접근할 수 없어 변경이 불가해진다. 변수들을 private으로 선언해두고 class 내부의 메소드만으로 변수를 접근 가능하게 하는 정보 은닉(Data Hiding)을 떠올리면 이해가 쉽다.