[Java] 직렬화(Serializable)


Development note/Java  2019. 7. 16. 09:00

안녕하세요. 명월입니다.


이 글은 Java에서 직렬화(Serializable)에 대한 글입니다.


예전에 C#에서 직렬화에 대해 글을 작성한 적이 있습니다.

링크 - [C#] 직렬화 (Serialization)


개념은 C#과 마찬가지로 할당된 클래스를 바이너리화하는 것을 직렬화라고 합니다. 이 직렬화를 하는 이유에 대해서는 클래스의 상태를 저장 혹은 소켓 통신을 통해 전송하기 위해서 사용합니다.

최근에는 Json형태로 데이터를 저장하는 경우가 많아서 직렬화를 잘 사용하지 않는데 Json형태로 저장하는 것은 Class에서 취득할 수 있는 부분까지 저장하는 것이고 private까지 저장하는 것은 아무래도 힘듭니다.


뭐 하고자 하면 Reflection을 통해서도 할 수 있겠지만, 그렇게 하는 것보다는 직렬화를 해서 클래스의 상태를 저장하는 것이 더 효율적이라고 할 수 있습니다.


직렬화는 클래스의 상태를 가장 편하게 데이터화 할 수 있으나 몇가지 단점이 있습니다.


첫번째는 이 직렬화된 데이터를 메모장에서 열어보면 사람이 이해하기 힘든 구조로 되어있습니다. 즉, 직렬화된 데이터는 역직렬화를 하기 전까지는 데이터를 알 수가 없습니다.

그의 반해 json은 String형태로 되어 있기 때문에 메모장으로 열어도 확인이 가능하고 직접 수정도 가능합니다. 직렬호 데이터는 아무래도 그게 힘드네요.


두번째는 플렛폼의 호환성을 좋지 않습니다. 즉, java에서 직렬화 시킨 데이터는 C#에서 역직렬화가 되지 않습니다. 정확하게는 되지 않는 것은 아닙니다만, 정보의 유실이 발생할 수 있습니다.

그리고 클래스가 변경되면 역직렬화시에 데이터 유실이 생기기 때문에 직렬화를 잘 사용하지를 않습니다.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerializableTest {
  public static void main(String[] args) {
    // Node 클래스 선언
    Node node = new Node();
    // data1에 Hello world를 넣음
    node.setData1("Hello world");
    // data2에 10을 넣음
    node.setData2(10);
    
    // 파일을 설정
    File file = new File("d:/work/test.dat"); 
    // 파일이 존재하면 삭제
    if(file.exists()) {
      file.delete();
    }
    
    // 직렬화
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
      try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
        oos.writeObject(node);
        // Node클래스를 byte 배열로 변환했다.
        byte[] data = baos.toByteArray();
        
        // 파일 스트림을 이용해 변환한 data를 파일로 저장한다.
        try (FileOutputStream stream = new FileOutputStream(file)) {
          stream.write(data, 0, data.length);
        }
      }
    } catch (Throwable e) {
      e.printStackTrace();
    }

    // 역직렬화
    try (FileInputStream stream = new FileInputStream(file)) {
      byte[] data = new byte[(int)file.length()];
      // 파일로부터 바이너리를 읽어 드린다.
      stream.read(data, 0, data.length);
      try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
        try (ObjectInputStream ois = new ObjectInputStream(bais)) {
          //byte 배열의 데이터를 Node의 클래스로 변환한다.
          Object objectMember = ois.readObject();
          Node node1 = (Node) objectMember;
          node.print();
        }
      }
    } catch (Throwable e) {
      e.printStackTrace();
    }

  }
}
// 클래스를 직렬화하려면 Serializable의 인터페이스를 상속받아야 한다.
class Node implements Serializable {

  // Serializable 인터페이스를 상속받으면 serialVersionUID를 설정해야 한다.
  private static final long serialVersionUID = 1L;
  private String data1;
  private int data2;

  public void setData1(String data1) {
    this.data1 = data1;
  }

  public void setData2(int data2) {
    this.data2 = data2;
  }

  public void print() {
    System.out.println("data1 = " + data1 + " data2 = " + data2);
  }
}

참조 - http://woowabros.github.io/experience/2017/10/17/java-serialize.html


자바로 직렬화한 데이터를 C#으로 역직렬화 해 보겠습니다.

동일하게 string data1과 int data2를 만들었는데 형식이 다르다고 에러가 나오네요.


여기까지 Java에서 직렬화(Serializable)에 대한 설명이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.