직렬화(Serialization) / 역직렬화(Deserialization)
1) 정의 : 객체를 바이트 배열의 데이터 타입으로 전송 가능한 형태로 만들어 전송하는 것을 의미한다.
* 객체는 바이트 형으로 변환하지 않으면 파일 저장 및 네트워크 전송이 불가능하다.
2) 스트림 : 객체 ↔ 바이트 배열 타입을 변환하여 데이터를 전송하는 통로를 의미한다.
3) 직렬화 : 객체 → 바이트 배열로 변환해 스트림을 통해 출력하는 것(파일, 네트워크 등 외부로)
4) 역직렬화 : 스트림을 통해 바이트 배열 → 객체로 변환해 원래의 객체 형태로 복원해 읽는 것
직렬화 가능한 클래스의 구현
package JavaPractice;
import java.io.*;
// 직렬화 클래스 만드는 법
class SerialInfo implements java.io.Serializable{ /* Serializable 인터페이스 이식 */
@Serial /* 직렬화를 하면 별도 serialVersionUID 선언 안할 시 java가 고유로 자동 생성하고 관리함 */
// 직접 UID를 선언 시 클래스가 변경되더라도 UID 변동 없어 관리가 용이, 역직렬화 가능
private static final long serialVersionUID = 1L;
// 필드 : 직렬화 대상(O)
String name;
int i;
private transient int password; /* 보안 등 기타 사유로 직렬화에서 제외하고 싶으면 transient를 붙임 */
// 메소드 : 직렬화 대상(X)
SerialInfo(String name, int i){
this.name = name;
this.i = i;
}
void printInfo(){
System.out.println("name : "+name);
System.out.println("i : "+i);
}
}
1) 우선 클래스를 직렬화 가능하게끔 하려면 Serializable 인터페이스를 implements 해야 한다.
* Serializable을 implements 한 클래스를 상속받은 서브 클래스의 경우도 가능
2) 직렬화 가능한 클래스의 대상 : 멤버 변수(O), 생성자 등 메서드(X)
3) 직렬화 클래스 내에서 직렬화 예외 처리 : 변수에 transient를 붙인다. (기타 보안 등의 사유로 필요시)
4) 그 밖에 클래스 내에 외부 객체를 멤버변수로 포함하는 경우 : java.util에서 제공하는 기본 클래스는 직렬화 가능
직렬화 실습
public class SerialTest {
public static void main(String[] args) {
try{
ObjectOutputStream out = /* 객체를 직렬화하여 쓰는 스트림 클래스에 객체를 담는 변수 out */
// 직렬화 객체를 쓸 수 있게 a.dat 파일을 쓰는 객체를 새로 생성하고 저장
new ObjectOutputStream(new FileOutputStream("SerialTest.dat"));
SerialInfo s1 = new SerialInfo("Jin", 1);
SerialInfo s2 = new SerialInfo("Tonic", 2);
// out 내 writeObject 메소드를 호출하여 객체를 직렬화하여 쓴다
out.writeObject(s1);
out.writeObject(s2);
// 파일을 닫고 저장
out.close();
}catch(Exception e){
System.out.println(e);
}
}
}
먼저 객체를 직렬화하여 담을 objectOutputStream 스트림 클래스 변수 out을 선언한다.
변수 out에는 FileOutputStream을 불러와 "SerialTest.dat"이라는 파일을 경로에 만들고,
이 파일을 objectOutputStream 클래스의 생성자 인자로 받아 저장한다.
이후 직렬화 클래스 SerialInfo의 객체인 s1과 s2를 생성자를 활용해 생성하고,
out 안의 메서드인 writeobject를 호출하여 객체를 직렬화하여 쓴다.
실행 결과
역직렬화의 구현
역직렬화 실습
역직렬화 시 직렬화한 순서대로 입력 및 출력이 진행되므로 순서에 유의할 수 있도록 하자.
아까와 동일하게 클래스는 직렬화 클래스인 SerialInfo를 활용해 구성했다.
package JavaPractice;
import java.io.*;
public class DeSerialTest {
public static void main(String[] args) {
try{
FileInputStream fis = new FileInputStream("SerialTest.dat");
// 객체를 역직렬화해 읽는 스트림 클래스의 객체를 변수 in에 저장
ObjectInputStream in = new ObjectInputStream(fis);
SerialInfo s;
// in.readObject를 통해 읽어온 역직렬화해 읽어온 값을 SerialInfo형으로 변환해 저장한 s 변수가
// null이 아닐때까지 반복 while문
while((s=(SerialInfo)in.readObject())!=null) s.printInfo();
fis.close();
in.close();
}catch (EOFException e){ /* 파일의 끝이라고 알려주는 End of File e 변수 */
System.out.println("더는 읽을 데이터가 없습니다");
}catch(Exception e){ /* 모든 에러타입에 대한 e 변수 */
System.out.println(e);
}
}
}
먼저 파일을 읽어올 FileInputStream 클래스 변수 fis를 선언해 아까 저장한 "SerialTest.dat"을 불러온다.
그리고 ObjectInputStream 클래스의 in 변수를 선언해 fis값을 생성자 인수로 받아 역직렬화를 한다.
while문을 통해 in 변수가 null 값을 불러올 때까지 s 변수를 선언해 객체를 저장하고 SerialInfo의 데이터 필드 값을 출력한다.
EOFException에 대한 예외 처리 블록을 만들어 파일 읽기가 끝났음을 표시하였다.
* EOFException(End of File Exception) : 읽어오는 파일에 더 이상 읽을 것이 없을 때 출력하는 에러
실행 결과
name : Jin
i : 1
name : Tonic
i : 2
더는 읽을 데이터가 없습니다
'DEV > Java' 카테고리의 다른 글
[java] java 메모리 구조와 공유 메모리의 이해 (0) | 2023.08.04 |
---|---|
[java] 멀티스레드(Multi thread)의 이해 / 구현 (0) | 2023.08.01 |
[java] java 접근 제어자 final, static, private (0) | 2023.07.27 |
[java] 접근 제어자의 이해와 구현 예제(Access Modifier) (0) | 2023.07.26 |
[java] java 다형성, 슈퍼/서브(부모/자식) 클래스 형변환 (0) | 2023.07.26 |