[Java] 직렬화(Serializable)
안녕하세요. 명월입니다.
이 글은 Java에서 직렬화(Serializable)에 대한 글입니다.
예전에 C#에서 직렬화에 대해 글을 작성한 적이 있습니다.
개념은 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)에 대한 설명이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.