무슨 소린지 몰라서 적으면서 이해해보려고 함
객체 직렬화(Serialization)이란? Java 객체를 바이트 스트림(byte stream)으로 변환하는 과정이다.
객체 -> byte Stream
이를 통해
1. 객체를 파일에 저장할 수 있고
2. 네트워크를 통해 객체를 전송할 수 있고
3. 객체를 데이터베이스에 저장할 수 있다.
이 객체 직렬화 / 역직렬화로 대체 뭘 해야하는지 기억하도록 하자. 개어렵다 진자
직렬화 방법
1. 직렬화 하려는 클래스가 Serializable 인터페이스를 구현해야한다.
package 연습문제;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
}
serialVersionUID 필드는 직렬화, 역직렬화를 수행할때 이 클래스의 버전??? 을 의미한다..
반드시 필요한 값은 아니지만, 명시적으로 선언하는 것이 좋다.
만약 역직렬화하려는 클래스의 버전이 기대하는 클래스의 버전과 다르다면 역직렬화에 실패한다.
static, long, 변수명 serialVersionUID는 반드시 지켜야한다.
private, final은 필수가 아니지만 권장사항이다.
2. ObjectOutputStream을 사용해서 객체를 직렬화한다.
밑의 이 안될 코드가 객체를 직렬화하는 코드다....
package 연습문제;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class objectoutputstream {
Person person = new Person("김철수", 25);
try(FileOutputStream fos = new FileOutputStream("person.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(person);
} catch(IOException e) {
e.printStackTrace();
}
}
보통 .ser 확장자를 사용한다.
try-with-resource 구문을 통해 자동으로 리소스를 닫아준다.
역직렬화(Deserialization) : 바이트 스트림을 다시 자바 객체로 변환한다.
Byte Stream -> 객체
package 연습문제;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class objectinputstream {
Person person = new Person("뽀르삐립", 25);
try(FileInputStream fis = new FileInputStream("Person.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
) {
Person person = (Person)in.readObject();
}catch(IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
????
주의사항과 고려사항
1. transient 키워드
특정 필드를 직렬화에서 제외하고 싶을 때 사용한다
package 연습문제;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
// transient를 사용하면 직렬화에서 제외한다
private transient String password;
Person() {}
Person(String name, int age) {
}
}
2.serialVersionUID
클래스의 버전 관리를 위해 사용된다.
위에 있는 private static final long serialVersionUID = 1L를 말한다
3. 보안 고려사항
직렬화된 데이터는 암호화되지 않는다.
민감한 정보는 transient로 표시하거나 암호화해야한다.
4. 성능 고려사항
직렬화 / 역직렬화는 리소스를 많이 사용할 수 있다.
대용량 데이터의 경우 JSON이나 Protocol Buffers같은 대안을 고려할 수 있다.
예외처리
직렬화 / 역직렬화 과정에서 발생할 수 있는 주요 예외
- IOException : 입출력 작업 중 발생하는 예외
- ClassNotFoundException : 역직렬화 시 클래스를 찾을 수 없을 때 발생함
- InvalidClassException : serialVersionUID가 일치하지 않을 때 발생함
실제 활용예제(매우 어려움)
package 연습문제;
import java.io.Serializable;
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private transient String password; // transient로 직렬화, 역직렬화에서 제외시킴
// setter
public Account(String id, String password) {
this.id = id;
this.password = password;
}
// getter
public String getId() {
return id;
}
public String getPassword() {
return password;
}
public String toString() {
return "Account{" + "id = '" + id + '\'' + ", password = '" + password + '\'' + '}';
}
}
Account 클래스를 만들고 Serializable 인터페이스를 포함한다.
private static final long serialVersionUID = 1L; 외엔 특별한게 없다.
문제는 다음이다. 많으니 2개로 쪼갠다. 둘 다 SerializationMain 클래스에 들어있다.
public class SerializationMain {
public static void init(Path directory) { // Path는 io.file.Path로 불러와야한다
// 저장할 경로의 파일 초기화
if(!Files.exists(directory)) { // 파일이 없으면?
// 파일을 생성한다.
try {
Files.createDirectories(directory);
}catch(IOException e) {
throw new RuntimeException(e);
}
}
}
public static <T> void save(Path filePath, T data) {
// 저장합니다, 저장하기 위해 객체를 바이트 스트림(byte stream)으로 변환합니다
try(FileOutputStream fos = new FileOutputStream(filePath.toFile());
//FileOutputStream 인스턴스에 매개변수로 받은 filePath를 넣고 toFile()메서드 적용
ObjectOutputStream oos = new ObjectOutputStream(fos);
// byte stream으로 만들기 위해 직렬화를 해주는 과정
) {
oos.writeObject(data); // 매개변수로 받은 data를 저장합니다.
}catch(IOException e) {
throw new RuntimeException(e);
}
}
public static <T> List<T> load(Path directory) {
//load니까 불러오는거겠죠..
if(Files.exists(directory)) {
// ??
try {
// 거대한 try - catch문 안에 작은 try-catch문이 있다
List<T> list = Files.list(directory)
.map(path -> {
try(
// input이니까 역직렬화같다
FileInputStream fis = new FileInputStream(path.toFile());
ObjectInputStream ois = new ObjectInputStream(fis);
) {
// Object타입 data를 만드는데 위의 ObjectInputStream타입 ois의 오브젝트를 읽는 메서드?
Object data = ois.readObject();
return (T) data;
} catch(IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}).toList(); // 에러 발생
return list; // 커다란 try-catch에서 선언한 list를 반환한다.. 위에 적힌걸 반환함
} catch(IOException e) {
throw new RuntimeException(e);
}
} else {
return new ArrayList<>();
}
}
끼야아아아악
'JAVA' 카테고리의 다른 글
| I/O - 보조 스트림 (0) | 2025.06.13 |
|---|---|
| 입출력 I/O - 바이트 기반 스트림 (1) | 2025.06.13 |
| Stram API의 map과 flatMap의 차이점 (0) | 2025.06.08 |
| 단일 책임 원칙(SRP)과 개방-폐쇄 원칙(OCP) (0) | 2025.06.05 |
| List<E> 컬렉션 (0) | 2025.06.04 |