Dev/Java

[java] 객체의 직렬화, 역직렬화

창문닦이 2019. 1. 31. 13:45

객체의 직렬화 : DB개념이 나오기전에는 파일을 모두 이와 같이 저장함

메모리에 생성된 클래스를 객체의 멤버변수의 현재 상태를 그대로 보존해서 파일에 저장하거나 네트워크를 통해 전달할 수 있는 기능

오로지 바이트 단위로만 데이터를 송수신 가능하다. 즉, 자바 시스템안에서 사용되는 데이터를 다른곳에서도 사용가능하도록

바이트 형태로 변환하는 기능과 바이트로 변환된 데이터를 다시 객체로 변환하는 (역직렬화) 를 포함하여 이야기한다.

장점은 객체 자체의 내용을 입출력 형식에 구애받지 않고 객체를 저장함으로써 영속성(프로그램을 종료해도 저장되어 있음)을 제공가능하며

객체 자체를 네트워크를 통해서 손쉽게 교환할 수 있다.

implements Serializable(인터페이스)로 구현(단, 메소드가 없다). 선언만 하면 됨

Collenction은 기본적으로 Serializable 구현된 인터페이스로 지님. 그래서 아래 코드에 구현 내용이 없어도 가능

import java.io.FileOutputStream;

import java.io.ObjectOutputStream;

import java.util.Hashtable;

public class Test1 {

public static void main(String[] args) {

try {

//Map 생성

Hashtable<String, String> h = new Hashtable<String, String>();

h.put("1", "배수지");

h.put("2", "김태리");

h.put("3", "천송이");//직렬화

//아웃풋파일 생성(파일은 character방식이라 h를 바로 넣을 수 없음. 유니코드로 된 데이터만 가능)

FileOutputStream fos = new FileOutputStream("d:\\doc\\out7.txt");

//파일을 메모리상에 있는 binary 형식으로 저장.

ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeObject(h);//upcast. 클래스는 데이터 타입이 Object

oos.close();

fos.close();

} catch (Exception e) {

// TODO: handle exception

}

}

}




역 직렬화 : 직렬화된 바이트형태의 데이터를 읽어와 객체로 변환하여 자바에서 사용가능하도록 만드는 기능

import java.io.FileInputStream;

import java.io.ObjectInputStream;

import java.util.Hashtable;

import java.util.Iterator;

public class Test2 {

public static void main(String[] args) {

try {

FileInputStream fis = new FileInputStream("d:\\doc\\out7.txt");//out7파일에 저장된건 Hashtable

ObjectInputStream ois = new ObjectInputStream(fis);

Hashtable<String, String> h = (Hashtable<String, String>)ois.readObject();//downcast

Iterator<String> it = h.keySet().iterator();

while(it.hasNext()){

String key = it.next();

String value = h.get(key);

System.out.println( key + " " + value);

}

fis.close();

ois.close();

} catch (Exception e) {

// TODO: handle exception

}

}

}




역직렬화는 개념을 누구나 꺼낼 수 있음. password와 같은 개념은 그때 그때 물어보게 해야한다

해당 예제에서는 age변수에 transient를 설정하면 -> default 값이 나옴

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

public class Test3 {

public static void main(String[] args) {

try {

//직렬화

FileOutputStream fos = new FileOutputStream("d:\\doc\\score.txt");

ObjectOutputStream oos = new ObjectOutputStream(fos);

//MyData ob = new MyData("배수지", 30);

oos.writeObject(new MyData("배수지",25,60));//클래스 객체 생성해서 바로 넣어주려고 오버로딩한 생성자를 만든 것

oos.writeObject(new MyData("박신혜",29,60));

oos.writeObject(new MyData("김태리",29,90));

oos.writeObject(new MyData("천송이",40,80));

oos.close();

fos.close();

//역직렬화

FileInputStream fis = new FileInputStream("d:\\doc\\score.txt");

ObjectInputStream ois = new ObjectInputStream(fis);

MyData ob = null;//클래스의 초기값은 null

while(true){

ob = (MyData)ois.readObject();//downcast

if(ob==null){//null이면 더이상 출력할 MyData없음

break;

}

System.out.println(ob.toString());

}

} catch (Exception e) {

// TODO: handle exception

}

}

}




implements Serializable가 반드시 작성되어야 함.

선언해주지 않는다면 직렬화가 되지 않아 writeObject로 입력 불가능

import java.io.Serializable;

public class MyData implements Serializable{//VO역할 하면 원래 GETTER, SETTER, 변수들만 있어야 하지만, 생성자 추가할 거임.

private static final long serialVersionUID = 1L;

private String name;

private transient int age;

private int score;

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public MyData(String name,int age ,int score){//오버로딩된 생성자. 초기화

this.name = name;

this.score = score;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getScore() {

return score;

}

public void setScore(int score) {

this.score = score;

}

@Override

public String toString() {

return String.format("%6s %4d %4d점",name,age,score);

}

}




Externalizable: Serializable 인터페이스에 하위 인터페이스같은 기능을 하되 좀 더 완벽한 제어가 가능함

writeExternal(), readExternal() 메소드를 정의해야 함

Externalizable보다 Serializable을 많이 사용함

import java.io.Externalizable;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInput;

import java.io.ObjectInputStream;

import java.io.ObjectOutput;

import java.io.ObjectOutputStream;

class DataTest implements Externalizable{

String name;

int age;

public DataTest(){}//기본생성자

public DataTest(String name, int age){//오버로딩된 생성자

this.name = name;

this.age = age;

}

@Override

public String toString() {

return name + ":" + age;

}

//호출 하지 않아도 자동적으로 실행되는 메소드 : readExternal(), writeExternal()

@Override

public void readExternal(ObjectInput in) throws IOException,

ClassNotFoundException {

name = (String)in.readObject();//downcast

age = in.readInt();//downcast 안해도 됨. 메소드에서 정수형으로 반환

System.out.println("readExternal....");

}

@Override

public void writeExternal(ObjectOutput out) throws IOException {

out.writeObject(name);

out.writeInt(age);

System.out.println("writeExternal....");

}

}

public class Test4 {

public static void main(String[] args) {

try {

DataTest ob = new DataTest("배수지", 25);//넣을 땐 오버로딩된 생성자로 객체 생성.

FileOutputStream fos = new FileOutputStream("d:\\doc\\out8.txt");

ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeObject(ob);

fos.close();

oos.close();

FileInputStream fis = new FileInputStream("d:\\doc\\out8.txt");

ObjectInputStream ois = new ObjectInputStream(fis);//직렬화 되었기 때문에 ObjectInputStream로 감싸줘야함

DataTest ob1 = (DataTest)ois.readObject();//꺼낼 때는 기본생성자로!

System.out.println(ob1.toString());

fis.close();

oos.close();

} catch (Exception e) {

System.out.println(e.toString());

}

}

}





다시 읽어보기) 자바 직렬화, 그것이 알고싶다. 훑어보기편 http://woowabros.github.io/experience/2017/10/17/java-serialize.html

'Dev > Java' 카테고리의 다른 글

[java] 채팅프로그램 만들기  (0) 2019.01.31
[java] 윈도우,swing  (0) 2019.01.31
[java] Stream  (0) 2019.01.30
[java] 스레드  (0) 2019.01.28
[java] ArrayList, List, Map, Generic, Exception  (0) 2019.01.27