Java Serializable : 자바 직렬화
  자바는 컴파일 후 생성된 .class파일은 우리가 만든 클래스의 정보를 담고 있다. 이는 class라는 하나의 데이터 타입이라고 볼 수 있다. 이 .class의 바이트가 가상머신에서 우리가 만들었던 클래스로 로딩되고 그 정보를 보고 객체(instanse)를 생성한다. 그리고 그 객체에 맞는 메모리가 할당된다. 아무튼 이 가상머신 내부에 존재한는 객체 메모리를 저장하거나 네트워크로 전송하기 위해서 한 줄로 이어진 바이트의 형태를 만드는 것, 그러니까 바이트 스트림을 만들어내는 것을 객체 직렬화라고 한다. 또한 보안같은 특별한 이유로 특정값을 직렬화에서 제외할 수 있는데 이것은 transient제어자를 붙이면 된다.


  직렬화 방법은 두가지가 있다. Serializable 또는 Externalizable이라는 Interface를 implements하여 구현할 수 있다. 두가지의 차이를 간단히 설명하자면 Serializable는 데이터의 저장과 복구가 자동으로 이루어진다. Externalizable 직렬화 권한은 주지만 데이터의 저장 및 복구 방법을 사용자가 구현해야한다.


 

아래 예제는 예전에 공부하면서 따라했던 코드이다.

 

Serializable예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SerialObject implements Serializable{
    private String name;
    private String dept;
    private String title;
 
    public SerialObject (String name, String dept, String title){
        this.name = name;
        this.dept = dept;
        this.title = title;
    }
 
    public String toString(){
        return name + ":" + dept + ":" + title;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
public class SerialObjectTest{
    public static void main(String[] args) throws Exception{
        FileOutputStream fos = new FileOutputStream("object.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
 
        SerialObject so1 = new SerialObject("갑""노동부""부장");
        SerialObject so2 = new SerialObject("을""노동부""신입");
 
        oos.writeObject(so1);
        oos.writeObject(so2);
        oos.close();
 
        FileInputStream fis = new FileInputStream("object.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
 
        SerialObject rso1 = (SerialObject)ois.readObject();
        SerialObject rso2 = (SerialObject)ois.readObject();
 
        System.out.println(rso1.toString());
        System.out.println(rso2.toString());
        ois.close();
    }
}

 

Externalizable예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ExternalObject implements Externalizable{
    private String name;
    private int age;
    private float height;
 
    public ExternalObject(String name, int age, float height){
        this.name = name;
        this.age = age;
        this.height = height;
    }
 
    public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException{
        name = (String)oi.readObject();
        age = oi.readInt();
        height = oi.readFloat();
    }
 
    public void writeExternal(ObjectOutput oo) throws IOException{
        oo.writeObject(name);
        oo.writeInt(age);
        oo.writeFloat(height);
    }
 
    public String toString(){
        return "이름:"+name+", 나이:"+age+ ", 키:"+height;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ExternalObjectTest{
    public static void main(String[] args) throws IOException, ClassNotFoundException{
        FileOutputStream fos = new FileOutputStream("external.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
 
        ExternalObject so1 = new ExternalObject("갑",43,170.25f);
        ExternalObject so2 = new ExternalObject("을",26,190.01f);
 
        oos.writeObject(so1);
        oos.writeObject(so2);
        oos.close();
 
        FileInputStream fis = new FileInputStream("external.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
 
        ExternalObject rso1 = (ExternalObject)ois.readObject();
        ExternalObject rso2 = (ExternalObject)ois.readObject();
 
        System.out.println(rso1.toString());
        System.out.println(rso2.toString());
        ois.close();
    }
}

위의 코드들에는 문제가 한가지 있다. serialVersionUID가 없다.

serialVersionUID는 명시적으로 선언해주면 InvalidClassException을 피할 수 있다. 컴파일러마다 다른계산법에 의해 serialVersionUID의 default값이 변화할 수 있기 때문이다. 또 serialVersionUID는 클래스 내부에서만 이용되므로 private 키워드를 붙여주는 것을 권고한다.

Posted by duehd88
,