Altiora Petamus

Serialization (직렬화) 본문

Java

Serialization (직렬화)

Haril Song 2021. 6. 3. 22:11

 

Serialization 이란?

  • 인스턴스의 상태를 그대로 파일 저장하거나 네트워크로 전송하고 (serialization) 이를 다시 복원(deserialization) 하는 방식
  • 자바에서는 보조 스트림을 활용하여 직렬화를 제공
  • ObjectInputStreamObjectOutputStream

 

 

 

Serializable 인터페이스

  • 직렬화는 인스턴스의 내용이 외부로 유출되는 것이므로 프로그래머가 해당 객체에 대한 직렬화 의도를 표시해야 한다.
  • 구현 코드가 없는 marker interface
  • transient : 직렬화 하지 않으려는 멤버 변수에 사용 (Socket 등 직렬화 할 수 없는 객체)

 

import java.io.*;

class Person {
    String name;
    String job;

    public Person() {
    }

    public Person(String name, String job) {
        this.name = name;
        this.job = job;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", job='" + job + '\'' +
                '}';
    }
}

public class SerializationTest {
    public static void main(String[] args) {

        Person personLee = new Person("이순신", "대표이사");
        Person personKim = new Person("김유신", "상무이사");

        try (FileOutputStream fos = new FileOutputStream("serial.txt");
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            
            // serialization
            oos.writeObject(personLee);
            oos.writeObject(personKim);

        } catch (IOException e) {
            e.printStackTrace();
        }

        try (FileInputStream fis = new FileInputStream("serial.txt");
             ObjectInputStream ois = new ObjectInputStream(fis)) {

            // deserialization
            Person pLee = (Person) ois.readObject();
            Person pKim = (Person) ois.readObject();

            System.out.println("pLee = " + pLee);
            System.out.println("pKim = " + pKim);

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }


    }
}

writeObject() 로 serialization, readObject() 로 deserialization 을 구현하고 있다.

 

위 코드를 실행해보자.

 

 

writeObject() 를 실행할 때 직렬화를 할 수 없다. 직렬화를 하기 위해서는 serializable interface 를 명시해줘야하기 때문이다.

 

class Person implements Serializable { ... }

이렇게 Serializable interface 를 구현하겠다고 명시해줘야 정상 동작한다.

 

 

생성된 파일을 보면 요상한 문자들이 써있는데 이것이 바로 정보를 직렬화한 것이며, deserialization 과정을 통해 정보를 복원하고 읽을 수 있게 된다.

 

그렇다면 Serializable interface 는 어떤 인터페이스이길래 이런 작업을 가능하게끔 하고 왜 명시해줘야하는걸까?

호기심을 잔뜩 억누르며 코드를 뜯어봤다.

 

...?

아무 것도 없었다...!

 

 

이게 도대체 어떻게 된 걸까?

 

Marker Interface

단지 Serializable interface 를 구현하고 있는 객체가 직렬화 가능하다고 표시해주는 역할만 하며, 아무 것도 구현하지 않고 단지 명시해주기 위해 사용되는 인터페이스를 "마커 인터페이스" 라고 한다.

 

 

transient

Socket 클래스는 직렬화할 수 없다. 그리고 만약 직렬화를 원하지 않는 필드가 있다면 transient 키워드를 사용해서 무시할 수 있다.

class Person implements Serializable {
    String name;
    transient String job;
...
}

transient 를 사용하면 기본값이 들어가게 된다.

 

 

만약 직접 직렬화를 구현하고 싶다면, Externalizable interface 를 구현하여 사용하면 된다.

 

'Java' 카테고리의 다른 글

[Design Pattern] Decorator  (0) 2021.06.05