본문 바로가기

언어/Java

필터스트림, 직렬화 예시

public class ObjectIOTest {
	public static void write() {
		/*
		 * 스트림: 바이트단위 출력스트림
		 * 필터스트림: 객체단위출력스트림
		 * 목적지 : 파일
		 */
		String fileName = "a.ser";
		ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(new FileOutputStream(fileName));
			oos.writeObject(new Date());
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(oos != null) {
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}	
		}	
	}

	public static void main(String[] args) {
		write();
	}
}

이 상태면 결과처럼 못알아들음

public class ObjectIOTest {
	public static void write() {
		/*
		 * 스트림: 바이트단위 출력스트림
		 * 필터스트림: 객체단위출력스트림
		 * 목적지 : 파일
		 */
		String fileName = "a.ser";
		ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(new FileOutputStream(fileName));
			oos.writeObject(new Date());
			Customer c = new Customer("id1", "p1", "n1", "a1");	
			// 직렬화 위해 Customer.java.에 implements Serializable
			oos.writeObject(c);
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(oos != null) {
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}	
		}	
	}

	public static void read() {
		String fileName = "a.ser";
		ObjectInputStream ois = null;
		
		try {
			ois = new ObjectInputStream(new FileInputStream(fileName));
			Object obj1 = ois.readObject();	// 객체를 녹이는 과정
			System.out.println(obj1.toString());
			
			Object obj2 = ois.readObject();
			System.out.println(obj2);	// obj2.toString() 자동호출됨
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			if(ois != null) {
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	
	public static void main(String[] args) {
		write();
		read();
	}


}
public class Customer extends Person implements Serializable {
	public static void main(String[] args) {
		Customer c = new Customer("id1", "p1", "n1", "a1");
		System.out.println(c);
	}
 }

결과

결과 첫번째 줄 : 얼린 시간의 시간

결과 블록부분 :  부모쪽은 serializable 안되서 null 값이 나왔음

- 부모쪽에서 제공되는 멤버변수는 객체 직렬화의 대상이 아님
customer가 Serializable를 구현해서 부모꺼는 직렬화가 안됨.
부모쪽에서 제공되는걸 직렬화하고 싶으면 Person에 implements Serializable 해야함.
부모쪽에 하면 Customer도 직렬화 가능하다

- 멤버변수로 쓰지말고 각 메서드마다 호출, 가공할 것

public class Person implements Serializable {

public class Customer extends Person {

위와 같이 수정하면 결과값 아래와 같이 변경된다

public class Customer extends Person {
	private String id;
	transient private String pwd;

※ 직렬화될 때 transient 넣어서 null 값으로 보이게 할 수 있음

결과

package ch18.sec10;

import java.io.Serializable;
	
public class Member implements Serializable {
	private static final long serialVersionUID = -622284561026719240L;
	private String id;
	private String name;
	
	public Member(String id, String name) {
		this.id = id;
		this.name = name;
	}
		
	@Override
	public String toString() { return id + ": " + name; }
}

위의 예제를 보면 Member는 Serializable 인터페이스를 구현하고 있다. 자바는 Serializable 인터페이스를 구현한 클래스만 직렬화할 수 있도록 제한한다. Serializable 인터페이스는 멤버가 없는 빈 인터페이스지만, 객체를 직렬화할 수 있다고 표시하는 역할을 한다. 객체가 직렬화될 때 인스턴스 필드값은 직렬화 대상이지만 정적 필드값과 transient로 선언된 필드값은 직렬화에서 제외되므로 출력되지 않는다.

public class xxx implements Serializable {
    public int field1;
    protected int field2;
    int field3;
    private field4;
    public static int field5;	// 정적필드는 직렬화에서 제외
    transient int field6;	// transient로 선언된 필드는 직렬화에서 제외
}

직렬화하면 일렬로 늘어선 바이트 데이터 아래와 같이 된다.

field1 field2 field3 field4

serialVersionUID 필드

직렬화할 때 사용된 클래스와 역직렬화할 때 사용된 클래스는 기본적으로 동일한 클래스여야 한다.

만약 클래스의 이름이 같더라도 클래스의 내용이 다르면 역직렬화에 실패한다.

public class Member implemets Serializble {
	int field1;
    int field2;
}
// 위의 Member 클래스로 생성한 객체를 직렬화하면
// 아래의 Member 클래스로 역직렬화할 수 없다. 아래 클래스에는 field3;가 있기 때문 
public class Member implemets Serializble {
	int field1;
    int field2;
    int field3;
}

클래스 내용이 다르다 할지라도 직렬화된 필드를 공통으로 포함하고 있다면 역직렬화할 수 있는 방법이 있다.

두 클래스가 동일한 serialVersionUID 상수값을 가지고 있으면 된다.

public class Member implemets Serializble {
	static final long serialVersionUID = 1;
	int field1;
    int field2;
}
// 직렬화 가능 
public class Member implemets Serializble {
	static final long serialVersionUID = 1;
	int field1;
    int field2;
    int field3;
}

※ 이클립스 serialVersionUID 자동 생성 기능 있음, 두번째꺼 누르면 된다/

결과
얘도 만들라고 에러 발생
결과

'언어 > Java' 카테고리의 다른 글

기본자료형과 참조형의 차이  (0) 2023.08.10
Product 예제 4  (0) 2023.08.09
필터스트림, 객체직렬화  (0) 2023.08.09
메타클래스, File 정보 가져오기  (0) 2023.08.09
FileCopy 예제  (0) 2023.08.09