본문 바로가기

Java dev/Java Basic

Serialization


▣ Serialization


   - 메모리상에 생성된 클래스객체의 멤버 변수의 값을 네트웍이나 파일로 저장할 수 있는 기능 제공
   - 객체직렬화가 필요한 객체는 반드시 Serializable 인터페이스를 구현해야 한다. 하지만 Serializable 인터페이스는 객체 직렬화가 제공되어야 함을 자바 가상머신에게 알려주는 열활만 하며 별도로 구현해야하는 메소드는 없다.
   - 객체 직렬화를 실행 할때 관련된 클래스도 객체 직렬화를 수행한다.
   - RMI를 통한 원격객체 통신, Beans 설계시 상태 정보 저장등에 효율적으로 쓰인다.
  

1. 기본적인 Object Serialization

import java.io.*;

public class UnitIn implements Serializable{
 private int i;
 private String name;
 
 public UnitIn(int d, String s){
  i = d;
  name = s;
  System.out.println(name + " 생성자가 호출되었습니다: ");
 }
 
 public String toString(){
  return "이름은 " + name + " : " + i;
 }
 
 public static void main(String args[]){
  UnitIn u1, u2;
  u1 = new UnitIn(1,"개구리 소년 : 왕눈이");
  u2 = new UnitIn(2,"개구리 소녀 : 아로미");
 
  try{
   ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("unit.ser"));
   out.writeObject(u1);
   out.writeObject(u2);
   out.close();
   
   System.out.println("객체를 파일에 기록했습니다.");  

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


2. 레퍼런스 변수의 Object Serialization
   - Reference 변수가 가리키고 있는 클래스도 Serializable Interface를 구현해야 함.


-------------------- Unit1.java --------------------
import java.io.*;

public class Unit1 implements Serializable{
 private String name;
 private SubUnit[] unit_array;
 
 public Unit1(String s, SubUnit[] u_arr){
  name = s;
  unit_array = u_arr;
  System.out.println("생성자가 호출되었습니다: " + name);
 }
 
 public String toString(){
  String retStr;
 
  retStr = "이름은 " + name + " -> ";
  for(int i=0; i < unit_array.length; i++)
   retStr += unit_array[i].toString() + " : ";
   
  return retStr;
 }
 
 public static void main(String args[]){
  Unit1 u1, u2;
  SubUnit[] sub1 = { new SubUnit("개구리"), new SubUnit("왕눈이"), new SubUnit("아로미") };
  SubUnit[] sub2 = { new SubUnit("슈퍼톡톡"), new SubUnit("둥가")};
 
  u1 = new Unit1("연못", sub1);
  u2 = new Unit1("영어", sub2);
 
  try{
   ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("unit.ser"));

   out.writeObject(u1);
   out.writeObject(u2);
   out.close();
   
   ObjectInputStream in = new ObjectInputStream(new FileInputStream("unit.ser"));

   Unit1 u3, u4;

   u3 = (Unit1)in.readObject();
   u4 = (Unit1)in.readObject();

   System.out.println("다시 복원합니다");  

   System.out.println(u3);
   System.out.println(u4);
  } catch(Exception e) {
   e.printStackTrace();
  }
 }
}


-------------------- SubUnit.java --------------------
import java.io.*;

public class SubUnit implements Serializable{
 private String unit_name;
 
 public SubUnit(String s){
  unit_name = s;
 }
 
 public String toString(){
  return unit_name;
 }
}



3-1. transient 키워드는 직렬화의 대상에서 변수를 제외시켜준다.

-------------------- Unit3.java --------------------
import java.io.*;

public class Unit3 implements Serializable{
 private String name;
 transient String passwd; 
 
 public Unit3(String s, String p){
  name = s;
  passwd = p;
  System.out.println(name + " 생성자가 호출되었습니다");
 }
 
 public String toString(){
  return "이름은 " + name + " : 패스워드 : " + passwd;
 }
 
 public static void main(String args[]){
  Unit3 u1, u2;
  u1 = new Unit3("강북구","1000");
  u2 = new Unit3("강남구","2000");
 
  try{
   ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("unit.ser"));
   
   out.writeObject(u1);
   out.writeObject(u2);
   out.close();
   
   ObjectInputStream in = new ObjectInputStream(new FileInputStream("unit.ser"));

   Unit3 u3, u4;

   u3 = (Unit3)in.readObject();
   u4 = (Unit3)in.readObject();

   System.out.println("----------- 다시 복원한 후의 값 ----------");  
   System.out.println(u3);
   System.out.println(u4);
  } catch(Exception e) {
   e.printStackTrace();
  }
 }
}



3-2. 객체 직렬화 데이터 클래스의 분리
------------------ Serial1.java ------------------
import java.io.*;

public class Serial1 {
 public static void main(String[] args) throws IOException {

  Person p = new Person("너구리", 20, "오동통하고 쫄깃함");

  System.out.println();
  System.out.println("객체 직렬화");
  System.out.println("---------------------------------");
  System.out.println("Person's 이름: " + p.name);
  System.out.println("Person's 나이: " + p.age);
  System.out.println("Person's 비고: " + p.temp);
  System.out.println("---------------------------------");

  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("rich.ser"));
  oos.writeObject(p);
  oos.flush();

  System.out.println();
  System.out.println("객체 직렬화가 다 되었습니다.");

  p = null;

  ObjectInputStream ois = new ObjectInputStream(
   new FileInputStream("rich.ser"));
  try {
   p = (Person) ois.readObject();
  } catch(ClassNotFoundException cnfe) {
   System.err.println("Persion 클래스를 찾지 못했습니다.");
  }

  System.out.println();
  System.out.println("객체 복원");

  System.out.println();
  System.out.println("객체 복원 후의 결과");
  System.out.println("---------------------------------");
  System.out.println("Person's 나이: " + p.name);
  System.out.println("Person's 이름: " + p.age);
  System.out.println("Person's 비고: " + p.temp);
  System.out.println("---------------------------------");
 }
}

class Person implements Serializable {
 public String name;
 public int age;
 public transient String temp;

 public Person(String name, int age, String temp) {
  this.name = name;
  this.age = age;
  this.temp = temp;
 }
}



4. 동일한 클래스 명에서의 충돌을 막기 위한 클래스의 버전 관리
   - serialver 툴 사용하기

------------------ Serial2.java 클래스의 수정 ------------------
import java.io.*;

public class Serial2 {
 public static void main(String[] args) throws IOException {

  Person p = null;

  ObjectInputStream ois = new ObjectInputStream(new FileInputStream("rich.ser"));
  try {
   p = (Person) ois.readObject();
  } catch(ClassNotFoundException cnfe) {
   System.err.println("Persion 클래스를 찾지 못했습니다.");
  }

  System.out.println();
  System.out.println("객체 복원");

  System.out.println();
  System.out.println("객체 복원 후의 결과");
  System.out.println("---------------------------------");
  System.out.println("Person's 나이: " + p.name);
  System.out.println("Person's 전화번호: " + p.phone);
  System.out.println("Person's 이름: " + p.age);
  System.out.println("Person's 비고: " + p.temp);
  System.out.println("---------------------------------");
 }
}

class Person implements Serializable {
 public String name;
 public String phone;
 public int age;
 public transient String temp;

 public Person(String name, String phone, int age, String temp) {
  this.name = name;
  this.phone = phone;
  this.age = age;
  this.temp = temp;
 }
}


------------------ Serial3.java ------------------
import java.io.*;

public class Serial3 {
 public static void main(String[] args) throws IOException {

  Person p = null;

  ObjectInputStream ois = new ObjectInputStream(new FileInputStream("rich.ser"));
  try {
   p = (Person) ois.readObject();
  } catch(ClassNotFoundException cnfe) {
   System.err.println("Persion 클래스를 찾지 못했습니다.");
  }

  System.out.println();
  System.out.println("객체 복원");

  System.out.println();
  System.out.println("객체 복원 후의 결과");
  System.out.println("---------------------------------");
  System.out.println("Person's 나이: " + p.name);
  System.out.println("Person's 전화번호: " + p.phone);
  System.out.println("Person's 이름: " + p.age);
  System.out.println("Person's 비고: " + p.temp);
  System.out.println("---------------------------------");
 }
}

class Person implements Serializable {
 public String name;
 public String phone;
 public int age;
 public transient String temp;

 static final long serialVersionUID = 5126197534689646959L;

 public Person(String name, String phone, int age, String temp) {
  this.name = name;
  this.phone = phone;
  this.age = age;
  this.temp = temp;
 }
}


5. 객체의 네트워크 전송
-------------------- Unit.java --------------------
import java.io.*;

public class Unit implements Serializable{
 private int i;
 private String name;
 
 public Unit(int d, String s){
  i = d;
  name = s;
 }
 
 public String toString(){
  return "이름은 " + name + " : " + "좋아하는 숫자 " + i;
 }
}


-------------------- Client.java --------------------
//실행 : java Client 211.44.123.164 4000

import java.io.*;
import java.net.*;

public class Client {
  public static void main(String[] args) throws IOException {
    try {
 if (args.length != 2) throw new IllegalArgumentException("인자의 수가 다름");
   
 String host = args[0];
 int port = Integer.parseInt(args[1]);
 System.out.println(host + " : " + port);
     
 Socket s = new Socket(host, port);
   
 ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
     
 Unit u = new Unit(1,"너구리");

 oos.writeObject(u);
 oos.flush();
 s.close();
   }

   catch (Exception e) {
      System.err.println(e);
      System.err.println("사용법: java Client <hostname> <port:4000>");
    }
  }
}


-------------------- Server.java --------------------
import java.io.*;
import java.net.*;
import java.util.*;

public class Server{
 public final static int SERVER_PORT = 4000;
 
 public static void main(String args[]){
  ServerSocket serverSock;
  Socket  sock;
  ObjectInputStream ois;
 
  try{
   serverSock =  new ServerSocket(SERVER_PORT);  
   
   while(true){
                                          
                                           System.out.println("서버가 작동 되었습니다.");

    sock = serverSock.accept();
     
    ois = new ObjectInputStream(sock.getInputStream());
     
    Unit u = (Unit)ois.readObject();
     
    System.out.println("네트워크 전송된 객체는 " + u.toString());
     
    sock.close();

    serverSock.close();
   }
  } catch(IOException e){
   System.err.println(e);
  } catch (ClassNotFoundException e){
   System.err.println(e);
  } 
 }
}