직렬화(Serialization)란?
각자 PC의 OS마다 서로 다른 가상 메모리 주소를 갖기 때문에, `Referece Type`의 데이터들은 인스턴스를 전달할 수 없다.
이런 문제를 해결하기 위해선 주소값이 아닌 `Byte` 형태로 직렬화된 객체 데이터를 전달해야 한다.
자바에서 직렬화(Serialization)란 객체를 바이트 스트림으로 변환하여 파일, 데이터베이스, 네트워크 등을 통해 저장하거나 전송할 수 있게하는 과정이다.
직렬화된 객체는 모두 파일 저장이나 네트워크 전송 시 파싱이 가능한 기본형(Primitve Type)이 되며, 역직렬화(Deserialization) 과정을 통해 원래 객체로 복원할 수 있다.
직렬화를 하는 경우는 주로 다음과 같다.
- 객체 지속성
JVM 메모리에 있는 객체를 영속화 할 수 있다. - 네트워크 전송
객체를 네트워크를 통해 다른 JVM으로 전송할 수 있다. - 캐싱
객체 직렬화하여 저장함으로써 데이터베이스 조회를 줄일 수 있다.
Serializable 인터페이스 사용 예시
직렬화하려는 클래스에 `Serializable` 인터페이스를 구현해야한다.
`Serializable` 인터페이스는 아무 메서드도 정의하지 않고,
단지 해당 객체가 직렬화 가능하다는 표시로 사용된다. ( = 마커 인터페이스)
public interface Seralizable {}
아래는 `Serializable` 인터페이스 사용 예시이다.
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 직렬화 버전 관리
private String name;
private int age;
private String password;
// ...
}
`Serializable` 인터페이스를 상속받은 `Person` 클래스는 직렬화 가능하다는 것을 의미한다.
⭐️ 객체 내 직렬화 대상은 `Serializable` 인터페이스를 상속 받은 객체, Primitive Type 데이터이다.
⭐️ static 필드는 직렬화 되지 않는다. 클래스의 상태가 아닌 인스턴스의 상태만 직렬화된다.
- 만약에, Person 객체 내에 `Serializable`을 상속받지 않은 객체가 멤버 변수로 있다면 이는 직렬화 할 수 없다.
ㄴ`InvalidClassException`가 발생할 것이다. - 참고로, `String`은 Primitibe Type이 아니지만 `Serializable`을 상속받았기 때문에 직렬화 가능하다.
ㄴ 기본형 래퍼 클래스, 문자열 및 관련 클래스, 컬렉션 클래스, 날짜 및 시간 관련 클래스 등은 `Serializable`을 상속받았다. - `serialVersionUID`는 `static`으로 선언되어 직렬화에 포함하지 않는다.
ㄴ하지만, 직렬화 된 객체에 클래스의 메타데이터로 포함되어 있다.
위의 예시에서는, 클래스의 모든 멤버변수가 직렬화 대상이 된다.
transit 키워드 사용 예시
하지만 위 예시에서 `password` 와 같이 민감한 데이터는 직렬화 시 제외시킬 필요가 있다.
보안상의 이유나 기타 이유로 직렬화 대상에서 제외하고 싶다면 `transient` 키워드를 사용하면 된다.
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 직렬화 버전 관리
private String name;
private int age;
private transient String password;
// ...
}
위의 예시에서 `password` 변수는 `transient` 키워드를 붙여 직렬화 대상에서 제외된다.
참고로, `transient` 키워드가 포함되어 있는 멤버 변수는 역직렬화 과정에서 기본값으로 초기화된다.
serialVersionUID 예시
위의 예시들에서 `Serializable` 인터페이스를 상속받은 객체의 멤버 변수 중 `serialVersionUID`를 주의 깊게 볼 필요가 있다.
이는 자바에서 직렬화된 객체의 버전을 식별하기 위해 사용되는 고유한 식별자이다.
직렬화된 객체를 역직렬화 할 때 클래스의 호환성을 확인하는데 사용된다.
`serialVersionUID` 주요 목적
- 버전 관리를 통한 호환성 유지
직렬화된 객체를 역직렬화할 때, 클래스가 변경되었더라도 동일한 `seriallVersionUID`를 가지면 호환성이 유지가 된다. - 클래스 변경 감지
만약 `seriallVersionUID`가 다른 것을 역직렬화 하게 되면 JVM은 `InvalidClassException`을 던진다.
이는 클래스가 직렬화된 객체와 호환되지 않음을 나타낸다.
만약 `seriallVersionUID`를 선언하지 않으면 JVM이 자동으로 생성한다. 하지만 자동생성된 값은 클래스 구조에 따라 달라지므로 클래스가 변경될 때마다 값이 달라질 수 있다. 때문에 개발자가 직접 관리하는 것이 좋다.
(예시 1) seriallVersionUID 선언하기
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 직렬화 버전 관리
private String name;
private int age;
private transient String password;
// ...
}
위와 같이 `seriallVersionUID`를 명시적으로 선언할 수 있다.
인스턴스 객체와는 독립적인 값이면서 클래스 수준에서 버전 관리를 위해 `static`으로 선언한다.
이때 이 값을 `final`로 선언하여 변경되지 않도록 보장해야 한다.
(예시 2) 만약 예시 1에서 새로운 필드를 추가하면?
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private transient String password;
private String email; // 새롭게 추가된 필드
// ...
}
email 필드를 추가했음에도 `seriallVersionUID`는 여전히 같다.
때문에 버전이 `1`인 객체를 역직렬화 할 수 있다.
하지만, 역직렬화된 객체는 새 필드 `email`에 대해 기본 값(null)을 갖게 된다.
(예시 3) 만약 예시 1에서 버전을 달리 하면?
class Person implements Serializable {
private static final long serialVersionUID = 2L; // 직렬화 버전 관리
private String name;
private int age;
private transient String password;
// ...
}
java.io.InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
`serialVersionUID`를 2로 변경한 경우, 예시 1에서 직렬화 한 객체를 예시 3의 클래스로 역직렬화 하려고 하면 `InvalidClassException`을 발생시킨다. 자바가 클래스의 `serialVersionUID`값이 달라졌음을 인식하고, 역직렬화를 거부했기 때문에 발생하는 예외이다.
💡 직렬화에 포함되지 않는 `serialVersionUID`. 직렬화 된 객체의 버전을 어떻게 알 수 있는가?
`serialVersionUID`는 `static`으로 선언되기 때문에 직렬화되지 않는다.
대신, 클래스에 대한 메타데이터로 직렬화되는 데이터와 함께 저장된다.
역직렬화 시 자바는 직렬화된 데이터에 포함된 `serialVersionUID`의 버전을 확인하고 호환성을 판단한다.
'Language > Java' 카테고리의 다른 글
record 클래스 (Java 14) (0) | 2024.12.13 |
---|---|
동기화(synchronization)와 락(Lock) (1) | 2024.12.11 |
Java의 스레드(Thread) (0) | 2024.12.10 |
Error & Exception (1) | 2024.12.09 |
가비지 컬렉션 (GC; Garbage Collection) (0) | 2024.12.08 |