12장. 직렬화 - GOAL
객체 직렬화란 자바가 객체를 바이트 스트림으로 인코딩하고(직렬화)
그 바이트 스트림으로부터 다시 객체를 재구성하는(역직렬화) 메커니즘이다.
직렬화된 객체는 다른 VM에 전송하거나 디스크에 저장한 후 나중에 역직렬화할 수 있다.
직렬화가 품고 있는 위험과 그 위험을 최소화하는 방법에 대해 알아보자.
아이템89. 인스턴스 수를 통제해야 한다면 readResolve보다는 열거 타입을 사용하라
아이템 3의 싱글톤 패턴(Singleton pattern)을 보면, 싱글톤 패턴 클래스의 생성자는 오로지 하나의 인스턴스만 생성하도록 보장한다.
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ...}
public void leavingTheBuilding() {...}
}
하지만 이 클래스는 Serializable을 구현하게 되는 순간 싱글턴이 아니게 된다. 기본 직렬화를 쓰지 않거나 명시적인 readObject 메서드를 제공하더라도 소용이 없다. 어떤 ReadObject 메서드를 사용하더라도 초기화될 때 만들어진 인스턴스와 다른 인스턴스를 반환하게 된다.
readResolve
이때 readResolve 메서드를 이용하면 readObject 메서드가 만든 인스턴스를 다른 것으로 대체할 수 있다. 이때 readObject 가 만들어낸 인스턴스는 가비지 컬렉션의 대상이 된다.
// 인스턴스 통제를 위한 readResolve - 개선의 여지가 있다!
private Object readResolve() {
// 진짜 Elvis를 반환하고, 가짜 Elvis는 가비지 컬렉터에 맡긴다.
return INSTANCE;
}
한편 여기서 살펴본 Elvis 인스턴스의 직렬화 형태는 아무런 실 데이터를 가질 필요가 없으니 모든 인스턴스 필드는 transient 로 선언해야 한다. 그러니까 readResolve 메서드를 인스턴스의 통제 목적으로 이용한다면 모든 필드는 transient로 선언해야 한다.
만일 그렇지 않으면 역직렬화(Deserialization) 과정에서 역직렬화된 인스턴스를 가져올 수 있다. 즉, 싱글턴이 깨지게 된다.
해결책은 enum
하지만 enum을 사용하면 모든 것이 해결된다. 자바가 선언한 상수 외에 다른 객체가 없음을 보장해주기 때문이다. 물론 AccessibleObject.setAccessible 메서드와 같은 리플렉션을 사용했을 때는 예외다.
// 열거 타입 싱글턴 - 전통적인 싱글턴보다 우수하다.
public enum Elvis {
INSTANCE;
private String[] favoriteSongs = {"Hound Dog", "Heartbreak Hotel"};
public void printFavorites() {
System.out.println(Arrays.toString(favoriteSongs));
}
}
물론 인스턴스 통제를 위해 readResolve 메서드를 사용하는 것이 중요할 때도 있다. 직렬화 가능 인스턴스 통제 클래스를 작성해야 할 때, 컴파일 타임에는 어떤 인스턴스들이 있는지 모를 수 있다. 이 때는 열거 타입으로 표현하는 것이 불가능하기 때문에 readResolve 메서드를 사용할 수 밖에 없다.
결론
불변식을 지키기 위해 인스턴스를 통제해야 한다면 가능한 한 열거 타입을 사용하자.
여의치 않은 상황에서 직렬화와 인스턴스 통제가 모두 필요하다면 readObject 메서드를 작성해 넣어야 하고, 그 클래스에서 모든 참조 타입 인스턴스 필드를 transient로 선언해야 한다.
'Java > 이펙티브 자바' 카테고리의 다른 글
[이펙티브자바 - 아이템90] 직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라 (0) | 2022.02.06 |
---|---|
[이펙티브자바 - 아이템88] readObject 메서드는 방어적으로 작성하라 (0) | 2022.02.06 |
[이펙티브자바 - 아이템87] 커스텀 직렬화 형태를 고려해보라 (0) | 2022.02.05 |
[이펙티브자바 - 아이템86] Serializable을 구현할지는 신중히 결정하라 (0) | 2022.02.05 |
[이펙티브자바 - 아이템85] 자바 직렬화의 대안을 찾으라 (0) | 2022.02.05 |