객체의 직렬화(Serialization)

예숑·2023년 12월 24일
0

JAVA - File

목록 보기
7/7
post-thumbnail

⭐️Serialization

객체의 직렬화라고 한다.
차례대로 읽고 쓰는 것이다.
객체를 바이트 단위로 일렬로 쭉 세울 수 있는 것이다.

→ 객체를 byte 단위로 쪼개서 File 에 전송해서 저장하고, 다시 내보내서 객체를 복구시킨다.

Serializable : 직렬화를 지원하는 애들만이 사용이 가능하고, 이를 분간해주는 마크인터페이스이다.

💜ObjectStream

ObjectInputStream, ObjectOutputStream : 객체를 전부 읽고 쓰는 스트림이다.

→ 가장 상위의 Stream 이다.
→ byte 연산이다.
→ 객체의 직렬화를 기반으로 한다.

💜Serializable

객체의 직렬화는 직렬화를 지원하는 객체만 읽고 쓰는 것이 가능하다.
대부분의 class들이 직렬화에 대해 대비하고 있지만 분간이 안될 때 Serializable을 이용해서 알 수 있다.

package home;

public class MyObjEx {
	private String value;
	private int num;
	
	public MyObjEx(String value, int num) {
		super();
		this.value = value;
		this.num = num;
	}

	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}

	@Override
	public String toString() {
		return "MyObjEx [value=" + value + ", num=" + num + "]";
	}	
}
package home;

import java.io.Closeable;
import java.io.IOException;

public class IOUtils {
	public static void closeAll(Closeable...c) {
		for(Closeable temp : c) {
			try {
				temp.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

위와 같은 MyObjEx(직렬화를 위한 클래스) 와 IOUtils(자원 해제를 위한 클래스) 클래스를 일단 만든다.

package home;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class MyObjectIOEx1  {
	private static String file = "myObj.dat";
	
	public static void write() {
		//Serializable 구현하지 않으면 에러 : NotSerializableException
		MyObjEx obj = new MyObjEx("abc", 100);
		
		FileOutputStream fos = null;
		ObjectOutputStream oos = null;
		
		try {
			fos = new FileOutputStream(file);
			oos = new ObjectOutputStream(fos);
			
			oos.writeObject(obj);
			oos.flush();
			oos.reset();
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			IOUtils.closeAll(oos,fos);
		}
	}
	public static void read() {
		
	}
	public static void main(String[] args) {
		write();
	}
}

→ 위 코드를 실행하면 위 사진과 같은 오류가 발생한다.
이는 MyObjEx 클래스가 직렬화를 지원받고 있지 않기때문이다.

reset( ) : 하지 않으면 다른 객체를 써도 안써지고 이전에 쓰인게 계속 호출되기에 꼭 해줘야 한다.
flush( ) 와 reset( ) 은 꼭 해주기!

package home;

import java.io.Serializable;

public class MyObjEx implements Serializable{
	private String value;
	private int num;
	
	public MyObjEx(String value, int num) {
		super();
		this.value = value;
		this.num = num;
	}
    
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	@Override
	public String toString() {
		return "MyObjEx [value=" + value + ", num=" + num + "]";
	}	
}

→ 오류를 수정하기 위해서는 위 코드와 같이 Serializable을 지원받고 있으면 된다.
→ implements Serializable : 직렬화를 구현하게 되어 실행 가능하다.

<ObjectInputStream, ObjectOutputStream 의 주의사항>
: 파일 당 객체 1개만 사용해야한다.
여러개 써도 되지만 read 할때 제대로 된다는 복장이 없다.
→ 여러개를 쓰고 싶을 때는 Vector 에 넣어서 쓰면 된다.
(Vector 가 Serializable를 구현하고 있어서 문제는 없다.)
→ But 제네릭(원소)이 Serializable를 구현하고 있지 않으면 문제 생긴다.
( 즉, 모두 Serializable를 구현하고 있어야한다.)

package home;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Vector;

public class MyObjectIOEx1  {
	private static String file = "myObj.dat";
	
	public static void write() {
		//Serializable 구현하지 않으면 에러 : NotSerializableException
		Vector<MyObjEx> vec = new Vector<MyObjEx>();
		
		vec.add(new MyObjEx("abc", 100));
		vec.add(new MyObjEx("def", 100));
		vec.add(new MyObjEx("ghi", 100));
		vec.add(new MyObjEx("jkl", 100));
		
		FileOutputStream fos = null;
		ObjectOutputStream oos = null;
		
		try {
			fos = new FileOutputStream(file);
			oos = new ObjectOutputStream(fos);
			
			
			oos.writeObject(vec);
			oos.flush();
			oos.reset();
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			IOUtils.closeAll(oos,fos);
		}
	}
	public static void read() {
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		
		try {
			fis = new FileInputStream(file);
			ois = new ObjectInputStream(fis);
			
			//? : 아무것나 해라(Object의 의미를 가진다.)
			//get 하면 Object로 나와서 형변환 해야함
			Vector<?> o = (Vector<?>)ois.readObject();
			
			System.out.println(o);
		} catch(IOException e) {
			e.printStackTrace();
		} catch(ClassNotFoundException e) {
			e.printStackTrace();
		}
		finally {
			IOUtils.closeAll(ois, fis);
		}
	}
	public static void main(String[] args) {
		write();
		//read();
	}
}

⭐️ClassNotFoundException


→ file에는 멤버변수만 저장이 가능하다.
나머지는 class 파일에 저장되는데 class파일 없이 file을 복구하면 ClassNotFoundException이 발생한다.

💜serialVersionUID


→ class 파일 생성 당시의 serialVersionUID의 값과 file의 serialVersionUID의 값이 다르면 InvalidClassException이 발생한다.
→ 임의로 우리가 직접 지정하면 예외가 발생하지 않는다.

0개의 댓글

관련 채용 정보