1. 개요
의 serialVersionUID의 속성 직렬화하는 데 사용되는 식별자이다 / A의 객체 직렬화 직렬화 클래스.
이 빠른 사용방법(예제)에서는 serialVersionUID 가 무엇인지, 예제를 통해 사용 방법에 대해 설명합니다.
2. 시리얼 버전 UID
간단히 말해, serialVersionUID 속성을 사용하여 Serializable 클래스의 버전을 기억 하여로드 된 클래스와 직렬화 된 객체가 호환되는지 확인합니다.
다른 클래스 의 serialVersionUID 속성은 독립적입니다. 따라서 다른 클래스가 고유 한 값을 가질 필요는 없습니다.
다음으로 몇 가지 예제를 통해 serialVersionUID 를 사용하는 방법을 알아 보겠습니다 .
직렬화 가능한 클래스를 만들고 serialVersionUID 식별자를 선언하는 것으로 시작하겠습니다 .
public class AppleProduct implements Serializable {
private static final long serialVersionUID = 1234567L;
public String headphonePort;
public String thunderboltPort;
}
다음으로 두 개의 유틸리티 클래스가 필요합니다. 하나는 AppleProduct 객체를 String 으로 직렬화하고 다른 하나는 해당 String 에서 객체를 역 직렬화하는 것입니다 .
public class SerializationUtility {
public static void main(String[] args) {
AppleProduct macBook = new AppleProduct();
macBook.headphonePort = "headphonePort2020";
macBook.thunderboltPort = "thunderboltPort2020";
String serializedObj = serializeObjectToString(macBook);
System.out.println("Serialized AppleProduct object to string:");
System.out.println(serializedObj);
}
public static String serializeObjectToString(Serializable o) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
}
public class DeserializationUtility {
public static void main(String[] args) {
String serializedObj = ... // ommited for clarity
System.out.println(
"Deserializing AppleProduct...");
AppleProduct deserializedObj = (AppleProduct) deSerializeObjectFromString(
serializedObj);
System.out.println(
"Headphone port of AppleProduct:"
+ deserializedObj.getHeadphonePort());
System.out.println(
"Thunderbolt port of AppleProduct:"
+ deserializedObj.getThunderboltPort());
}
public static Object deSerializeObjectFromString(String s)
throws IOException, ClassNotFoundException {
byte[] data = Base64.getDecoder().decode(s);
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data));
Object o = ois.readObject();
ois.close();
return o;
}
}
우리는 실행하여 시작 SerializationUtility.java 저장 (직렬화)를 AppleProduct의 에 객체 문자열 instanc , 전자 바이트 사용하여 인코딩 Base64로를 .
그런 다음 해당 String 을 deserialization 메서드에 대한 인수로 사용하여 DeserializationUtility.java 를 실행 하여 주어진 String 에서 AppleProduct 개체 를 재 조립 ( 탈 렬화 )합니다 .
생성 된 출력은 다음과 유사해야합니다.
Serialized AppleProduct object to string:
rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta
HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3
J0cQB+AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd
Gh1bmRlcmJvbHRQb3J0MjAyMA==
Deserializing AppleProduct...
Headphone port of AppleProduct:headphonePort2020
Thunderbolt port of AppleProduct:thunderboltPort2020
이제 AppleProduct.java 에서 serialVersionUID 상수를 수정하고 이전에 생성 된 동일한 문자열에서 AppleProduct 객체를 다시 직렬화 해제 해 보겠습니다 . DeserializationUtility.java를 다시 실행 하면이 출력이 생성됩니다.
Deserializing AppleProduct...
Exception in thread "main" java.io.InvalidClassException: com.baeldung.deserialization.AppleProduct; local class incompatible: stream classdesc serialVersionUID = 1234567, local class serialVersionUID = 7654321
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at com.baeldung.deserialization.DeserializationUtility.deSerializeObjectFromString(DeserializationUtility.java:24)
at com.baeldung.deserialization.DeserializationUtility.main(DeserializationUtility.java:15)
클래스 의 serialVersionUID 를 변경하여 버전 / 상태를 수정했습니다. 결과적으로 deserialization 중에 호환되는 클래스가 발견되지 않았고 InvalidClassException 이 발생했습니다.
경우 의 serialVersionUID가 A의 제공되지 직렬화 클래스, JVM은 자동으로 하나를 생성합니다. 그러나 serialVersionUID 값 을 제공 하고 클래스 변경 후이를 업데이트하여 serialization / deserialization 프로세스를 제어 할 수 있도록하는 것이 좋습니다. 이후 섹션에서 자세히 살펴 보겠습니다.
3. 호환 가능한 변경 사항
기존 AppleProduct 클래스에 새 필드 lightningPort 를 추가해야한다고 가정 해 보겠습니다 .
public class AppleProduct implements Serializable {
//...
public String lightningPort;
}
새 필드를 추가하는 중이므로 serialVersionUID 를 변경할 필요가 없습니다 . 이는 deserialization 프로세스 중에 lightningPort 필드 의 기본값으로 null 이 할당 되기 때문 입니다 .
이 새 필드의 값을 인쇄하도록 DeserializationUtility 클래스를 수정 해 보겠습니다 .
System.out.println("LightningPort port of AppleProduct:"
+ deserializedObj.getLightningPort());
이제 DeserializationUtility 클래스를 다시 실행하면 다음과 유사한 출력이 표시됩니다.
Deserializing AppleProduct...
Headphone port of AppleProduct:headphonePort2020
Thunderbolt port of AppleProduct:thunderboltPort2020
Lightning port of AppleProduct:null
4. 기본 시리얼 버전
Serializable 클래스에 대해 serialVersionUID 상태를 정의하지 않으면 Java는 클래스 이름, 인스턴스 필드 등과 같은 클래스 자체의 일부 속성을 기반으로 하나를 정의합니다.
간단한 Serializable 클래스를 정의 해 보겠습니다 .
public class DefaultSerial implements Serializable {
}
이 클래스의 인스턴스를 다음과 같이 직렬화하면 :
DefaultSerial instance = new DefaultSerial();
System.out.println(SerializationUtility.serializeObjectToString(instance));
이것은 직렬화 된 바이너리의 Base64 다이제스트를 인쇄합니다.
rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz/mdAIAAHhw
이전과 마찬가지로 다이제스트에서이 인스턴스를 역 직렬화 할 수 있어야합니다.
String digest = "rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpY"
+ "WxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz/mdAIAAHhw";
DefaultSerial instance = (DefaultSerial) DeserializationUtility.deSerializeObjectFromString(digest);
그러나이 클래스를 일부 변경하면 직렬화 호환성이 손상 될 수 있습니다. 예를 들어이 클래스에 private 필드를 추가하면 :
public class DefaultSerial implements Serializable {
private String name;
}
그런 다음 동일한 Base64 다이제스트를 클래스 인스턴스로 역 직렬화하려고하면 InvalidClassException이 발생합니다.
Exception in thread "main" java.io.InvalidClassException:
com.baeldung.deserialization.DefaultSerial; local class incompatible:
stream classdesc serialVersionUID = 9045863543269746292,
local class serialVersionUID = -2692722436255640434
이러한 원치 않는 비 호환성 때문에 항상 Serializable 클래스 에서 serialVersionUID 를 선언하는 것이 좋습니다 . 이렇게하면 클래스 자체가 발전함에 따라 버전을 유지하거나 발전시킬 수 있습니다.
5. 결론
이 빠른 기사에서는 직렬화 된 데이터의 버전 관리를 용이하게하기 위해 serialVersionUID 상수를 사용하는 방법을 설명했습니다 .