Java Object Stream과 직렬화

유방현·2024년 10월 28일

Java Object Stream과 직렬화

1. 기본 개념

1.1 직렬화(Serialization)

  • 객체를 바이트 형식으로 변환하는 과정
  • 파일 저장이나 네트워크 전송을 위해 사용
  • ObjectOutputStream을 통해 구현

1.2 역직렬화(Deserialization)

  • 바이트 스트림을 객체로 복원하는 과정
  • 저장된 데이터나 수신된 데이터를 객체로 변환
  • ObjectInputStream을 통해 구현

2. ObjectOutputStream 사용

2.1 기본 사용법

public class ObjectOutputExample {
    public void saveObject() {
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("object.dat"))) {
            // 객체 생성
            Person person = new Person("John", 30);
            
            // 객체 직렬화
            oos.writeObject(person);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2 여러 객체 직렬화

public class MultipleObjectOutput {
    public void saveObjects() {
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("objects.dat"))) {
            // 여러 객체 저장
            List<Person> people = Arrays.asList(
                new Person("John", 30),
                new Person("Jane", 25)
            );
            oos.writeObject(people);
        }
    }
}

3. ObjectInputStream 사용

3.1 기본 사용법

public class ObjectInputExample {
    public void loadObject() {
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("object.dat"))) {
            // 객체 역직렬화
            Person person = (Person) ois.readObject();
            System.out.println(person);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

3.2 여러 객체 역직렬화

public class MultipleObjectInput {
    public void loadObjects() {
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("objects.dat"))) {
            // 리스트로 저장된 객체들 읽기
            List<Person> people = (List<Person>) ois.readObject();
            people.forEach(System.out::println);
        }
    }
}

4. Serializable 구현

4.1 기본 구현

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

4.2 transient 필드 사용

public class User implements Serializable {
    private String username;
    private transient String password; // 직렬화에서 제외
    
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}

5. 실전 활용 예제

5.1 객체 상태 저장/복원

public class GameStateManager {
    public void saveGameState(GameState state) {
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("game.save"))) {
            oos.writeObject(state);
        }
    }
    
    public GameState loadGameState() {
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("game.save"))) {
            return (GameState) ois.readObject();
        }
    }
}

5.2 객체 깊은 복사

public class ObjectCloner {
    public static <T extends Serializable> T deepCopy(T object) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            return (T) ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException("복사 실패", e);
        }
    }
}

6. 주의사항과 모범 사례

6.1 버전 관리

public class VersionedClass implements Serializable {
    // 클래스 구조 변경 시 serialVersionUID 업데이트
    private static final long serialVersionUID = 2L;
    
    // 새로운 필드 추가
    private String newField;
}

6.2 보안 고려사항

  • 민감한 데이터는 transient 선언
  • 역직렬화 시 타입 안전성 검증
  • 신뢰할 수 있는 소스의 데이터만 역직렬화

0개의 댓글