직렬화란 자바의 객체를 네트워크 상에서 주고받게 하기 위하여 메모리에 저장된 객체를 바이너리 형식으로 변환하는 것을 뜻합니다. 역직렬화는 당연히 반대의 과정입니다.
이렇게 변환된 직렬화된 객체는 하드디스크에 저장하거나 네트워크 상으로 전송하여 다른 컴퓨터에서 사용하도록 할 수 있습니다.
직렬화를 하려면 대상 클래스가 Serializable
인터페이스를 구현해야 합니다. 참고로 ArrayList
를 비롯한 몇몇 자바 클래스에서는 이미 Serializable 구현이 되어 있습니다. 객체 단위보다는 List
단위로 객체 직렬화-역직렬화를 하는 것이 효율적일 것입니다.
객체 직렬화-역직렬화 시 serialVersionUID
가 서로 맞아야 제대로 작동합니다. 일반적으로 따로 선언하지 않아도 자바 내부에서 자동으로 버전을 생성하지만 이 경우 클래스의 잦은 내용 변경 시 문제가 발생하게 됩니다.
자바에서는 serialVersionUID
를 사용자가 임의의 값으로 설정하여 내부에서 관리하는것을 추천한다고 합니다. 이클립스의 기능을 이용하면 기본 아이디를 만들거나 임의로 생성된 아이디를 사용할 수 있습니다.
예제는 자바의 List
를 사용해서 게시판을 만들어보는 것입니다. 애초에 그냥 자바에서 만든 List
라면 해당 객체가 프로그램이 실행되었을 때 만들어지며 프로그램이 꺼지면 메모리에서 사라지고 안에 들어있던 내용은 영원히 다시 볼 수 없을 것입니다.
그러나 직렬화를 사용하여 글이 작성되면 List
의 내용을 하드디스크에 저장하고 프로그램을 껐다 다시 실행해도 하드디스크에 있는 직렬화된 파일을 읽어 List
의 내용을 복구할 수 있습니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package blog.seri; | |
import java.io.Serializable; | |
// 직렬화하려는 클래스는 반드시 Serializable을 implements 해야 한다. | |
public class Article implements Serializable{ | |
/** | |
* 이클립스에서 Adds a generated serial version ID 기능을 이용하면 | |
* 자동으로 시리얼 아이디를 생성해준다. | |
*/ | |
private static final long serialVersionUID = -83252522547L; | |
public int seq; | |
public String writer, message; | |
public Article(int seq, String writer, String message) { | |
super(); | |
this.seq = seq; | |
this.writer = writer; | |
this.message = message; | |
} | |
@Override | |
public String toString() { | |
return seq + "\t" + writer + "\t" + message; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package blog.seri; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.ObjectInputStream; | |
import java.io.ObjectOutputStream; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Scanner; | |
public class Board { | |
static List<Article> list = new ArrayList<>(); | |
public static void main(String[] args) throws IOException, ClassNotFoundException { | |
// 직렬화 입력받기: 파일로부터 직렬화된 내용을 읽어 객체로 변환시킨 뒤 | |
// 메모리에 적재시킨다. | |
try { | |
readFromFile(); | |
} catch(FileNotFoundException e) {} | |
Scanner s = new Scanner(System.in); | |
while(true) { | |
prompt(s); | |
} | |
} | |
private static void prompt(Scanner s) throws FileNotFoundException, IOException { | |
displayBoard(); | |
System.out.print(">> "); | |
String command = s.nextLine(); | |
if(command.equalsIgnoreCase("w") || command.equalsIgnoreCase("write")) { | |
write(s); | |
} else if (command.equalsIgnoreCase("x") || command.equalsIgnoreCase("exit")) { | |
System.exit(0); | |
} | |
} | |
private static void write(Scanner s) throws FileNotFoundException, IOException { | |
System.out.print("작성자 이름? "); | |
String writer = s.nextLine(); | |
System.out.print("글 내용? "); | |
String message = s.nextLine(); | |
int seq = 0; | |
if(list.size() != 0) { | |
seq = list.get(list.size() – 1).seq + 1; | |
} | |
list.add(new Article(seq, writer, message)); | |
System.out.println(); | |
// 직렬화 출력하기: 글이 작성되었으면 메모리의 객체를 직렬화한 뒤 | |
// 물리적인 파일로 하드디스크에 저장한다. | |
saveToFile(); | |
} | |
private static void displayBoard() { | |
System.out.println("순서\t글쓴이\t메시지"); | |
System.out.println("———————–"); | |
if(list.size() == 0) { | |
System.out.println("[아직 글이 없습니다.]"); | |
} | |
list.forEach((x) -> { | |
System.out.println(x); | |
}); | |
} | |
private static void saveToFile() throws FileNotFoundException, IOException { | |
// 파일 출력 스트림 객체를 만든 후, 이름을 "board.ser"라고 지정하고 | |
// fos를 바탕으로 오브젝트 출력 스트림을 생성한 뒤 writeObject 한다. | |
try(FileOutputStream fos = new FileOutputStream("board.ser"); | |
ObjectOutputStream oos = new ObjectOutputStream(fos);) { | |
oos.writeObject(list); | |
} | |
} | |
@SuppressWarnings("unchecked") | |
private static void readFromFile() throws FileNotFoundException, IOException, ClassNotFoundException { | |
// 파일 입력 스트림 객체를 만든 후, 이름을 "board.ser"라고 지정하면 이 파일로부터 읽겠다는 뜻이며 | |
// fis를 바탕으로 오브젝트 입력 스트림을 생성한 뒤 readObject 한다. | |
// 오브젝트 형태로 읽으면 안에 있는 내용이 무슨 타입인지 정확히 알기 어려우므로 타입 캐스팅 해준다. | |
try(FileInputStream fis = new FileInputStream("board.ser"); | |
ObjectInputStream ois = new ObjectInputStream(fis);) { | |
list = (List<Article>) ois.readObject(); | |
} | |
} | |
} |
껐다 켜도 내용이 그대로 남아있다.
1개의 댓글
IT 기술면접(일반) 예상문제: CS 일반, 개발 상식, 네트워크 (작성중) - BGSMM · 2020년 6월 12일 12:00 오후
[…] 직렬화란 자바의 객체를 네트워크 상에서 주고받게 하기 위하여 메모리에 저장된 객체를 바이너리 형식으로 변환하는 것을 뜻합니다. 이렇게 변환된 직렬화된 객체는 하드디스크에 저장하거나 네트워크 상으로 전송하여 다른 컴퓨터에서 사용하도록 할 수 있습니다. […]