본문 바로가기

JAVA

불변객체(Immutable Object)를 사용해야하는 이유

1. 불변객체(Immutable Object)란?


불변객체는 말그대로 변하지않는 객체로 객체가 생성된후 내부 상태가 변하지 않는 객체를 의미한다.

 

불변객체는 Setter 메소드를 제공하지 않으며, 내부상태를 제공하는 메소드는 제공하지 않거나 방어적 복사

(defensive-copy)를 통해 제공한다.

 

불변이라는 키워드를 보며 바로 생각난것은 바로 final 예약어이다.

 

하지만 단순히 final 예약어를 사용해서 불변객체를 만드는 것이 아니다.

 

final 예약어는 변수에 사용시 값을 수정할 수 없는 상수로 만들어주고,
메소드에 사용시 Overriding을 할 수 없고,
클래스에 사용시 상속이 불가능 하다.

 

즉, 객체 선언시에 final 예약어를 사용한다 하더라도, 객체 내부상태는 변경할 수 있는것이다.

 

[불변객체 사용시 장점]

1. 쓰레드에 안전하여 멀티 쓰레드 환경에서 동기화를 고려하지 않아도 된다.

2. 불변객체를 필드로 사용할 때 방어적 복사가 필요없다.

3. 불변객체는 내부상태가 변경되지 않으므로, Map Key 와 Set 요소로 사용하기에 적합하다.

4. 불변객체를 한번 메모리에 할당하게 되면 같은 객체를 계속 호출하여도, 새롭게 할당하지 않아도 되므로 GC       의 성능을 높힐 수 있다.

 

2. 불변객체를 생성하는 방법


불변객체를 생성하기 위한 전략이다.

 

1. setter 메소드를 사용하지 마라

2. 모든 필드를 final 과 private를 사용해서 선언해라

3. 클래스를 final 로 선언하여 Overriding을 막아라

4. 객체를 생성하기 위한 생성자 혹은 정적 팩토리 메소드를 추가해라

5. 인스턴스 필드에 가변객체가 포함된다면 방어적 복사를 이용하여 전달해라

 

방어적 복사 vs Unmodifiable Collection

 

방어적 복사 vs Unmodifiable Collection

불변객체를 공부하다보니 방어적 복사라는 키워드가 자주등장하여 따로 포스팅 하게 되었다. 불변객체(Immutable Object)를 사용해야하는 이유 불변객체(Immutable Object)를 사용해야하는 이유 1. 불변

dev-cool.tistory.com

 

불변클래스를 만들어 보자

 

public final class ImmutableClass {
    /*
    * Integer 와 String 은 immutable 객체로
    * 값을 변경하는 Setter 가 없어서 값이 변하지 않는다.
    * */
    private final Integer immutableField1;
    private final String immutableField2;
    private final Date mutableField;

    private ImmutableClass(Integer immutableField1, String immutableField2, Date mutableField){
        this.immutableField1 = immutableField1;
        this.immutableField2 = immutableField2;
        this.mutableField = new Date(mutableField.getTime());
    }

    public static ImmutableClass createImmutableClass(Integer immutableField1, String immutableField2, Date mutableField){
        return new ImmutableClass(immutableField1,immutableField2,mutableField);
    }

    public Integer getImmutableField1() {
        return immutableField1;
    }

    public String getImmutableField2() {
        return immutableField2;
    }

    /*
    * Date 는 가변 객체로 인스턴스 변수의 참조를 return 하지 않는다.
    * 대신에 new 예약어를 사용해서 방어적복사를 수행한다.
    * */
    public Date getMutableField() {
        return new Date(mutableField.getTime());
    }

    @Override
    public String toString() {
        return "immutableField1 = " + immutableField1 + ", immutableField2 = " + immutableField2 + ", mutableField = " + mutableField;
    }
}

 

public class Main {

    public static void main(String[] args) {
        ImmutableClass immutableClass = ImmutableClass.createImmutableClass(1,"cool",new Date());
        System.out.println(immutableClass);

        modiftyField(immutableClass.getImmutableField1(),immutableClass.getImmutableField2(),immutableClass.getMutableField());
        System.out.println(immutableClass);
    }

    private static void modifyField(Integer immutableField1, String immutableField2, Date mutableField){
        immutableField1 = 2;
        immutableField2 = "kim";
        //가변객체 Date 의 setter 메소드
        mutableField.setTime(2);
    }
}

 

실행 화면

 

불변객체를 생성하기위한 전략을 준수하여 불변객체를 생성한 후

객체의 상태를 바꾸는 메소드를 실행했지만, 내부상태는 변경되지 않은것을 확인할 수 있다.

 

불변객체를 사용했을때 이점을 생각해보면 가변적이어야 하는 타당한 이유가 존재하지 않는이상 되도록이면 불변으로 만들어야 하는것 같다.

 

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