-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
📌 [아이템 87] 커스텀 직렬화 형태를 고려해보라
✨ 핵심 내용
- 기본 직렬화 형태는 신중히 사용해야 한다.
- 기본 직렬화는 객체의 물리적 표현을 저장하므로, 내부 구현에 의존하게 되어 유지보수에 문제가 생긴다.
- 변경 예정인 내부 구조가 직렬화 형태에 포함되면, 해당 구현에 영원히 발이 묶이게 된다.
- 기본 직렬화는 객체의 논리적 상태와 물리적 상태가 같을 때에만 적합하다.
- 불변식을 보장하고 보안 문제를 방지하기 위해
readObject()메서드를 직접 정의해야 할 수 있다. - 직렬화 형태는 일종의 공개 API로 간주되므로,
@serial및@serialData태그를 활용해 문서화가 필요하다.
✅ 예제 코드 - 기본 직렬화 형태에 적합한 클래스
public class Name implements Serializable {
/**
* 성. null이 아니어야 함.
* @serial
*/
private final String lastName;
/**
* 이름. null이 아니어야 함.
* @serial
*/
private final String firstName;
/**
* 중간이름. 중간이름이 없다면 null.
* @serial
*/
private final String middleName;
}❌ 예제 코드 - 기본 직렬화에 부적절한 클래스
public final class StringList implements Serializable {
private int size = 0;
private Entry head = null;
private static class Entry implements Serializable {
String data;
Entry next;
Entry previous;
}
}✅ 개선된 커스텀 직렬화 코드
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeInt(size);
for (Entry e = head; e != null; e = e.next)
s.writeObject(e.data);
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
int numElements = s.readInt();
for (int i = 0; i < numElements; i++)
add((String) s.readObject());
}💡 새롭게 알게 된 점
- transient 키워드는 단순히 직렬화 제외를 위한 도구가 아니라, 논리 상태와 무관한 필드를 구분하기 위한 의도적 신호다.
📚 정리
- 기본 직렬화를 무조건 사용하지 말고, 논리적 표현과 물리적 표현의 일치 여부를 먼저 따져보자.
- writeObject/readObject를 직접 구현해 커스텀 직렬화 형태를 설계하는 것이 장기적인 유지보수에 유리하다.
- 직렬화는 한번 선택하면 바꾸기 어렵기 때문에, 직렬화 형태도 API 수준으로 진지하게 다뤄야 한다.
- 실제 프로젝트에서는 설정 파일이나 캐시, 복잡한 객체 상태 저장 시, 커스텀 직렬화 형태를 도입해 버전 관리와 유연성을 확보할 수 있다.
📢 댓글로 각자의 학습 내용을 공유해주세요!
Reactions are currently unavailable