본문 바로가기
Java/About Java

[Java] Immutable Object

by seaweed_one 2023. 2. 14.
728x90

안녕하세요. 씨위드입니다.

오늘은 불변객체(Immutable Object)의 정의와 특징 등에 대하여 알아보겠습니다.

 

Immutable Object 란?

불변객체란 전체 수명동안 상태가 변경되지 않은 상태로 유지되도록 보장된 객체입니다.

가장 중요한 것은 객체 생성 이후 내부의 상태가 변하지 않다는 것입니다.

경우에 따라서는 내부에서 사용하는 속성이 변화해도 외부에서 그 객체의 상태가 변하지 않은 것처럼 보인다면 불변 객체로 보기도 합니다.

불변객체는 내부 상태를 변경하는 메서드를 제공하지 않거나 방어적 복사를 통해 데이터를 제공합니다. 

Java에서는 대표적으로 String, 래퍼클래스(Integer, Long, Double 등)가 있습니다.

String을 조금 더 살펴볼까요?

String str = "HELLO";
str.toLowerCase();

toLowerCase() 함수 호출로 인해 우리가 생성한 str 객체가 변경되었을까요?

String 모든 공개 API는 새 문자열을 반환합니다.

해서 toLowerCase()라는 함수 호출 시에도 원래 문자열은 항상 동일하게 유지됩니다.

해당 함수 내부를 살펴보면 아래와 같이 return 문에서 new를 이용해 새로운 객체를 반환하는 것을 볼 수 있습니다.

 

그럼 불변 객체의 반대 개념은 무엇일까요?

바로 가변객체(Mutable Object)입니다.

가변객체는 객체 생성 이후에 내부 상태 변경이 가능한 객체를 뜻합니다.

대표적으로는  ArrayList, StringBuilder, StringBuffer 등이 존재합니다.

 

 

불변객체의 장점 

Thread-safe

멀티스레드 환경에서는 공유자원의 값을 서로 변경하여 문제가 발생하는 경우가 있습니다.

상태를 변경할 수 없기 때문에 스레드의 간섭으로 인한 문제가 발생하지 않습니다.

항상 동일한 값을 보장하기 때문에 동기화를 고려하지 않아도 된다는 장점을 가집니다.

예측 가능성

가변 객체는 값이 계속해서 변할 수 있기 때문에 객체의 값을 예측하기가 어렵습니다.

하지만 불변객체는 외부에서 객체를 변경할 수 없어 객체의 상태가 변경되지 않으니 신뢰성이 높습니다.

방어적 복사 불필요 

먼저 방어적 복사의 개념에 대해서는 아래 글에 설명해 두었습니다.

 

[Java] 얕은 복사 & 깊은 복사 & 방어적 복사

안녕하세요. 씨위드입니다. 오늘은 자바의 복사에 대하여 알아보겠습니다. 얕은 복사(Shallow Copy)란? 간단히 말하면 주소값을 복사하는 것입니다. 원본 객체를 참조하여 원본 객체에 종속적입니

seaweed-one.tistory.com

매개변수의 유효성 검사 전에 복사본을 만들어 복사본으로 유효성을 검사하게 됩니다.

멀티 스레드 환경에서 원본 객체 유효성 검사 후 복사본을 만드는 찰나에 다른 스레드가 원본 객체를 수정할 위험이 있기 때문인데 불변 객체 사용 시에는 해당 과정이 필요 없겠죠?

캐싱

캐시는 일반적으로 Java의 Map 구현과 유사한 키-값 쌍으로 구현됩니다.

위에서 경우에 따라서는 내부에서 사용하는 속성이 변화해도 외부에서 그 객체의 상태가 변하지 않은 것처럼 보인다면 불변 객체로 보기도 한다고 말씀드렸죠?

예를 들어, 비용이 큰 계산의 결과를 캐시 하기 위해 메모이제이션(Memoization)을 이용하더라도 그 객체는 여전히 불변하다고 볼 수 있습니다.

* Memoization: 프로그램이 동일한 계산 반복 시 이전 계산 값을 메모리에 저장, 동일계산 반복수행을 제거해 실행 속도를 향상시키는 기술 

 

 

불변 객체 생성 

1. setter 메서드 미제공

해당 메서드는 객체의 상태를 변경하기 위한 것으로 제공하지 않습니다.

2. private & final 필드 

모든 필드를 비공개 그리고 최종 필드로 선언합니다.

3. 메서드 재정의 불가

하위 클래스에서 메서드를 재정의하는 것을 허용하지 않습니다. 가장 쉬운 방법은 class 자체를 final로 만드는 것입니다.

4. 변경 가능한 필드가 있는 변경 불가능한 클래스에 주의

String, wrapper classes 등 변경할 수 없는 멤버는 getter 메서드에서 안전하게 반환할 수 있으나 변경 가능한 멤버의 경우 getter에서 새 객체에 복사한 후 반환합니다.

 

참조 : https://howtodoinjava.com/java/basics/how-to-make-a-java-class-immutable/

728x90