불변 객체(Immutable Object)

2021. 6. 4. 16:18Java/Etc

 

우리는 급변하는 세상 속에서 살고 있지만 그중에서도 절대 변하지 않았으면 하는 것은 있다.

많은 변화 속에 변하지 않는 그것 불변(Immutable)의 특징에 대해 알아보자.

 

불변 객체(Immutable Object) 란?

불변 객체란 '객체(Object)가 생성이 된 이후에 내부의 값 또는 상태를 변경할 수 없는 객체'로 한번 선언 및 초기화 후에는 절대 변경되지 않는 객체를 말한다.

그럼 이렇게 값이 변하지 않는 불변 객체의 특징에 대해 알아보자.

 

불변 객체의 대표는 String Class이다?

불변 객체 하면 제일 먼저 떠오르는 것이 바로 String이다.

하지만 혼동하지 말아야 할부분은 String Class는 값이 수정 가능한 변수이고 정확한 불변 객체는 리터럴(literal) " "이다.

String str; 	 	//String 변수 
str = "불변객체"; 	//"불변객체"를 전달받는 str변수 
str = new String("Immutable Object");

위 구문에서 보듯이 String 변수에는 값을 대입할 수 있으며 실제로 불변 객체라고 할 수 있는 부분은 변수에 대입된 "불변 객체", "Immutable Object"의 String 자료형의 리터럴 값인 것이다.

보통 불변 객체 하면 String이라고 지칭하는 이유는 다른 데이터 타입(Primitive Data Type)의 값과는 다르게 String 형태의 "" 리터럴 값 만이 불변의 특성을 가지고 있기 때문일 것이다.

이런 String Class의 여러 가지 특징은 아래 내용을 참고하면 된다.

 

About String Class

우리는 String 하면 문자열을 표현하는 데이터 타입(DataType)의 하나로 알고 간단하게 쓰고 있지만 String Class에는 다른 데이터 타입(Primitive Data Type)과는 다른 몇 가지의 특별한(?) 특징이 존재한다.

lovelettee01.tistory.com

단, 다른 데이터 타입 역시도 Wrapper Class를 이용하면 불변 객체로 생성할 수 있으니 참고하면 된다. (링크)

그럼 "literal" 이외에 사용 가능한 불변 객체(Immutable Object)를 생성하는 방법에 대해 알아보자.

 

불변 객체는 final 키워드를 통해 생성할 수 있다.

final 키워드를 통해 생성할 수 있는 항목은 Class, Method, Object, Field, Parameter이다

//Class에선언가능
final Class{ 
    final int FINAL_INT = 0;    //Field에선언가능
    final Class = new Class();  //Object에선언가능
    //Method 및 Parameter인자에 선언가능 
    public final method(final String str){
        ... 
    }
}

보통 final 키워드를 통한 불변 객체는 거의 모든 항목에 생성할 수 있다.

 

하지만 여기서도 한 가지 확인해야 하는 부분은 불변 객체는 한번 생성하면 그 값을 변경할 수는 없지만 new를 통한 참조형 객체를 생성하는 경우 해당 참조 값은 변경이 불가능하지만 참조 값을 통한 내부의 상태나 값을 변경하는 것은 가능하다는 점을 알아둬야 한다.

 

* 원시 데이터 타입(Primitive Data Type)

  • 값 자체를 나타내기 때문에 항목을 변경할 수 있는 Setter 함수를 생성하지 않는 것만으로도 암묵적인 불변 객체를 생성 가능함!
  • final 키워드를 통해 해당 항목에 변경 시도 시 오류(Exception)를 통해 불변 객체를 보다 정확하게 관리할 수 있다.

 

* 참조형 데이터 타입(Reference Data Type)

  • 참조형 데이터 타입의 경우는 원시 타입과 다르게 Setter를 작성하지 않는 것만으로는 불변 객체를 생성할 수 없다.
  • 참조 값은 불변이지만 참조 값을 통한 내부의 값 또는 상태를 변경할 수 있다.

위에서 볼 수 있듯이 final 키워드를 통해 간단하게 불변 객체를 생성할 수 있지만 불변이라는 이름에 맞게 생성하려면 몇 가지 생성 규칙이 있다.

 

불변 객체 암묵적 생성 규칙

  1. Setter 함수를 구현하지 않는다.
  2. 불변 객체를 생성할 부분의 접근제어자를 private로 지정해 외부 접근을 통한 값 변경 및 상속, 재정의를 방지한다.
  3. 객체 생성 시 생성자를 통한 초기화를 지원하지 않고 필요시 스태틱 팩토리 메서드를 통한 객체 생성을 유도한다.
  4. 내부의 상태 또는 값 변경 가능성이 존재하는 경우에는 방어적 복사(Defensive copy)를 통한 인스턴스 간의 불변 관계를 유지한다.
public class ImmutableClass{
    //불변 객체를 생성할 부분의 접근제어자를 private로 지정한다.
    private final String FINAL_STRING;
    private final int FINAL_INT;
    private final List<String> FINAL_LIST;
    private ImmutableClass(final String FINAL_STRING, final int FINAL_INT){
        this.FINAL_STRING = FINAL_STRING;
        this.FINAL_INT    = FINAL_INT;
        this.FINAL_LIST   = new ArrayList<String>();		
    }

    //스태틱 팩토리 메소드를 통항 객체생성
    public static ImmutableClass of(final String FINAL_STRING, final int FINAL_INT){
        return new ImmutableClass(FINAL_STRING, FINAL_INT);
    }

    //방어적 복사(Defensive copy)를 통한 List 객체 내부의 값을 변경하지 못하도록함.
    public List<String> getList() {
    	return Collections.unmodifiableList(FINAL_LIST);
    }
}

그럼 이렇게 불변 객체를 생성 관리하는 이유는 무엇일까??
마지막으로 불변 객체를 생성할 때의 장단점에 대해 알아보자.

 

불변 객체의 장단점

※ 장점

1. 보안적으로 유리하다.
- 일반적으로 외부에서 내부의 값이나 상태를 변경할 수 없기 때문에 보안적으로 유리하다.

2. 스레드 안정성 (Thread-safe)이 보장된다.
- 불변 객체를 쓰는 가장 큰 장점이라고 할 수 도 있으며 Multi-Thread 환경이 중요해진 만큼 각각의 Thread에 의해서 값이나 상태의 변경이 불가능하기 때문에 신뢰 가능한 데이터로 유지되어 안전하게 동작 가능하다.

3. 스레드 안정성(Thread-safe)이 보장되기 때문에 동기화 처리 없이 객체 공유가 가능하다.
- 스레드 안정성이 보장되기 때문에 내부적으로 동기화(Syncronized)에 대해서 고민을 할 필요가 없어지며 이로 인한 오버 헤드를 피할 수 있다.

4. 방어적 복사(Defensive copy)를 통한 객체 관리의 수고를 덜 수 있다.
- 참조 값을 통해 내부적인 상태를 변경 불가능하게 만들기 위하여 사용하는 방어적 복사의 로직을 구현할 필요가 없다.

5. 부수적 영향(Side Effect)을 줄일 수 있다.
- 값이 변동되면서 발생할 수 있는 여러 가지 '의도하지 않은 결과'에 대한 영상도를 줄일 수 있다.

6. GC(Garbage Collected)에 의한 성능을 향상할 수 있다.
- GC 동작시 Immutable 객체에 대해서는 내부적으로 성능 향상 효과를 볼 수 있다.

 

​※ 단점

1. 불필요한 메모리 사용량이 증가할 수 있다.
- 매번 새로운 객체를 생성해야 하기 때문에 불필요한 객체를 생성해 메모리 사용량이 증가할 수 있다.

 

마치며..

여러 문서를 둘러보며 느낀 점은 불변 객체의 사용은 필연적이다.
단점에 비해 많은 장점이 존재하는 불변 객체는 피치 못할 사정이 없는 한 모든 객체를 불변으로 만들어 사용하자!

'Java > Etc' 카테고리의 다른 글

문자열(String) Class 사용법  (0) 2021.08.09
About String Class  (0) 2021.05.22
프로그램에서 음수 표현 방식  (0) 2021.05.14