변하지 않는 객체
를 의미한다.재할당
은 가능하다.public static void main(String[] args){
Integer i1 = 1;
i1 = 2;
}
Integer 클래스는 자바의 대표적인 Immutable class 중 하나이다.
위의 예에서 i1에 '1'을 대입하여 초기화를 하고,
이후 다시 i1에 '2'를 할당하였다. 그렇다면 Integer i1은 변한 것일까?
정답은 '변하지 않았다'이다. 이는 i1이 값을 변경한 것이 아니라,
내부적으로 Integer객체를 새롭게 생성
하였기 때문이다.
이러한 특성을 갖는 객체를 '불변 객체'(Immutable)라고 한다.
Immutable 객체는 인스턴스 캐싱을 구현할 때 사용되는데, 이는 인스턴스를 공유하여 메모리를 절약하는데 효과가 있다.
인스턴스 캐싱이란?
반복적으로 사용되는 인스턴스를 미리 저장해 놓고 필요시 저장된 인스턴스를 사용하는 것
예를 들어 자바의 Integer 클래스는 내부적으로 인스턴스 캐싱을 사용하고 있는데,
일정 범위의 정수를 미리 생성하여 캐쉬 배열에 저장해 놓았다가, 어플리케이션에서 사용될 때 꺼내서 사용하는 형태
이다.
이때, 한 어플리케이션에서 '1'이라는 Integer 값을 100번 사용한다고 가정해보자.
Integer가 Immutable하지 않아서 값이 수시로 바뀐다면 끔찍한 부작용이 뒤따를 것이다.
때문에 인스턴스 캐싱에서는 Immutable class가 사용된다.
다음과 같이 처음 생성 후 사용되는 Integer 객체가 있다고 한다면,
public static void main(String[] args){
Integer i = new Integer(20);
System.out.println(i);
operate(i);
System.out.println(i);
}
private static void operate(Integer i) {
i = i + 1;
}
다음과 같이 i는 operate메소드에서 인자로 쓰이고 난 이후에도 값이 변하지 않는다.
20
20
이는 값이 변하지 않고 새롭게 생성되는 Immutable 특징 때문이다. 따라서 변경으로 인한 부작용을 근본적으로 방지
할 수 있다.
앞서 살펴본 2번의 이유로, 멀티 스레드 환경에서 안정성이 보장된다.
Immutable class는 다음과 같은 방법으로 직접 만들 수 있다.
public final class Immutable { //(1) final class
private final String name; //(2) private field
private final int age; //(3) final field
private final HashMap<Integer, String> map;
public String getName(){
return name;
}
public int getAge(){
return age;
}
public HashMap<Integer, String> getMap() {
return (HashMap<Integer, String>) map.clone();
//(6) getter 에서 clone() 사용
}
//(4) setter x
//(5) deep copy constructor
public Immutable(String name, int age, HashMap<Integer, String> map) {
this.name = name;
this.age = age;
HashMap<Integer, String> newMap = new HashMap<>();
for(Integer key : map.keySet()){
newMap.put(key, map.get(key));
}
this.map = newMap;
}
}
참고한 자료