final만 붙이면 불변 객체 아니야? 불변 객체(Immutable Object)를 알아보자

주리링·2022년 3월 1일
0

우테코 생존기

목록 보기
2/17
post-thumbnail

불변 객체란?

생성 후 상태를 바꿀 수 없는 객체
즉, 힙 영역에서 객체가 가리키고 있는 데이터 자체의 변화가 불가능한 것

ex) Money의 필드 int형 money는 한 번 값을 할당하면 변경할 수 없다.

public class Money {

	final private int money;

	private Money(final int money) {
		this.money = money;
	}

}

final만 붙이면 불변 객체 아니야?

가장 많이 사용하는 불변 객체는 바로 String입니다.

String name = "judy";
name = "juri";

이런 것이 가능한데, String은 왜 불변 객체일까요?

이는 name이 참조하는 “judy” 값이 변경되는 것이 아니라, “juri” 라는 새로운 객체를 만들고 그 객체를 name이 참조하게 하기 때문입니다.

즉, 불변 객체는 재할당은 가능하지만, 한 번 할당하면 내부 데이터를 변경할 수 없는 객체인 것이지요.

불변 객체를 사용하는 이유는?

  • thread-safe하며 synchronization issue가 없어요.
    => MultiThread 환경에서 synchronization처리 없이 객체를 공유 가능
  • 필드로 사용할 때 방어적 복사를 할 필요가 없어요.
    => 생성자, 접근 메소드에 대한 방어적 복사가 불필요
  • 해시코드가 지연 초기화를 사용하고 반환 값을 캐시하도록 허용해요.
    => 지연 초기화란? 필드의 초기화 시점을 그 값이 처음 필요할 때까지 늦추는 기법

불변 객체를 사용하는 방법

원시 타입만 있는 경우

필드에 final 키워드를 붙이고, Setter 제거하여 불변을 보장합니다.

	public class Money {

		final private int money;

		private Money(final int money) {
		this.money = money;
		}

	}

참조 타입이 있는 경우

  1. 참조 변수가 일반 객체인 경우

    public class Money {
    
    	final private Coin coin;
    
    	private Money(final Coin coin) {
    		this.coin = coin;
    	}
    
    }

    참조 변수인 객체도 불변 객체여야 합니다.

    public class Coin{
    
    	final private int coin;
    
    	private Coin(final int coin) {
    		this.coin = coin;
    	}
    
    }
  2. 배열인 경우

    생성자에서 Arrays.copyOf 를 이용하여 저장하고, getter에서 clone을 반환하도록 합니다.

    객체로 형성된 배열이라면, 객체 또한 불변 객체여야 합니다.

    public class Lotto {
    
        private final int[] lotto;
    
        public Lotto (final int[] lotto) {
            this.lotto = Arrays.copyOf(lotto,lotto.length);
        }
    
        public int[] getLotto () {
            return (lotto == null) ? null : lotto.clone();
        }
    }
  3. 리스트인 경우

    생성자에서 새로운 List값을 복사하여 상태를 저장하고,
    getter에서 값의 추가와 삭제가 불가능 하도록 Collections.unmodifiableList()를 사용합니다.

    객체로 형성된 리스트라면, 객체 또한 불변 객체여야 합니다.

    public class Lotto{
    
        private final List<Integer> lotto;
    
        public Lotto(final List<Integer> lotto) {
            this.lotto = new ArrayList<>(lotto);
        }
    
        public List<Integer> getLotto() {
            return Collections.unmodifiableList(lotto);
        }
    }

"Classes should be immutable unless there's a very good reason to make them mutable....If a class cannot be made immutable, limit its mutability as much as possible.” - Effective Java

참고참고
https://velog.io/@conatuseus/Java-Immutable-Object%EB%B6%88%EB%B3%80%EA%B0%9D%EC%B2%B4
http://www.javapractices.com/topic/TopicAction.do?Id=29

profile
코딩하는 감자

2개의 댓글

comment-user-thumbnail
2022년 3월 1일

잘봤습니다! 2번 3번의 경우에는 배열, 리스트 그자체는 불변이나 그 안에 있는 요소들까지 불변으로 만들기위해 clone과 collections.unmodifiable을 쓰신건가요?

1개의 답글