직렬화
객체를 연속된 바이트 데이터로 변환하는 것입니다.
반대로 바이트를 다시 객체로 복원하는 건 역직렬화(Deserialization)입니다.
왜 필요한가?
객체는 메모리에만 존재합니다. 이걸 저장하거나 전송하려면 바이트로 바꿔야 합니다.
[객체] ──직렬화──▶ [바이트 데이터] ──역직렬화──▶ [객체]
(메모리) (파일/네트워크) (메모리)
사용 예시
| 상황 | 설명 |
|---|---|
| 파일 저장 | 게임 세이브 데이터 저장 |
| 네트워크 전송 | 서버 ↔ 클라이언트 데이터 교환 |
| 캐시 | 객체를 Redis 등에 저장 |
| 깊은 복사 | 바이트로 변환 후 다시 객체로 복원 |
Java 예시
import java.io.*;
class Person implements Serializable { // 이거 필수!
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Main {
public static void main(String[] args) throws Exception {
Person original = new Person("김철수", 25);
// 직렬화 (객체 → 바이트)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(original);
byte[] bytes = bos.toByteArray();
System.out.println("바이트 크기: " + bytes.length); // 예: 82
// 역직렬화 (바이트 → 객체)
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Person restored = (Person) ois.readObject();
System.out.println(restored.name); // 김철수
System.out.println(restored.age); // 25
}
}
메모리 흐름
[직렬화]
┌──────────────┐
│ Person 객체 │
│ name: "김철수" │ ──▶ [0x7A, 0x3F, 0x12, 0x8B, ...]
│ age: 25 │ 연속된 바이트 배열
└──────────────┘
[역직렬화]
[0x7A, 0x3F, 0x12, 0x8B, ...] ──▶ ┌──────────────┐
│ Person 객체 │
│ name: "김철수" │
│ age: 25 │
└──────────────┘
파일에 저장하기
// 저장
FileOutputStream fos = new FileOutputStream("person.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(original);
oos.close();
// 불러오기
FileInputStream fis = new FileInputStream("person.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
Person loaded = (Person) ois.readObject();
ois.close();
깊은 복사에 활용
public static <T extends Serializable> T deepCopy(T obj) throws Exception {
// 직렬화
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
// 역직렬화 → 완전히 새로운 객체
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
}
객체를 바이트로 풀었다가 다시 조립하니까 모든 중첩 객체가 새로 생성됩니다.
주의사항
class Person implements Serializable {
String name;
transient String password; // 직렬화 제외
}
Serializable인터페이스 필수transient키워드로 특정 필드 제외 가능- 클래스 구조가 바뀌면 역직렬화 실패할 수 있음
요약
| 용어 | 의미 |
|---|---|
| 직렬화 | 객체 → 바이트 |
| 역직렬화 | 바이트 → 객체 |
| 목적 | 저장, 전송, 복사 |