From: juejin. Cn/post / 684490…
Alibaba Development Manual, (IV) OOP protocol, article 13 explains as follows:
[Mandatory] Do not modify the serialVersionUID field when serializing new attributes of the class to avoid anti-sequence failure; Change the serialVersionUID value if the upgrade is completely incompatible to avoid deserialization clutter. Note: Note that inconsistent serialVersionUID throws a serialization runtime exception.
First of all, it’s important to explain this rule. It’s not that you can’t change it, but that you can change it as you see fit. Let’s take a look at what the serialVersionUID is for.
serialization
Serialization is the process of converting a Java object into another form of data that can be used for storage or transmission. Since Java objects are stored in memory and there is no way to store or transfer them directly, deserialization resolves this problem by converting morphic data back to Java objects. Of course, this form can be a variety of formats, such as the well-known JSON, Byte, or our custom form, such as k-V form, as shown in the following figure.
Java Default serialization
Speaking of serialVersionUID, we have to refer to Java’s default serialization, which provides a serialization method by default in order to provide the storage and outgoing described above. As long as the serialized class implements the Java.io.Serializable interface, then you can do serialization and deserialization. I’ve briefly outlined the code to make it more intuitive (with some cuts).
User.java
public class User implements java.io.Serializable {
private String name;
public User(String name) {
this.name = name;
}
@Override
public String toString() {
returnname; }} Copy the codeCopy the code
SerializerTest.java
User user = new User("Code Maker's Notes.");
FileOutputStream fo = new FileOutputStream("user.bytes");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(user);
FileInputStream fi = new FileInputStream("user.bytes");
ObjectInputStream si = new ObjectInputStream(fi); user = (User) si.readObject(); Copy the codeCopy the code
The code is pretty straightforward,User
To achieve theSerializable
Interface, throughObjectOutputStream
Convert the class to bytecode and store ituser.bytes
And then use it againObjectInputStream
Take the bytecode fromuser.bytes
Read into memory.That’s pretty easy to doJava
Is it really useful? Of course, for exampleJava
Built-in remote call componentRMI
.
serialVersionUID
Finally, why can’t you easily change the serialVersionUID? The serialVersionUID is not set in the code above. So let’s tweak the example and test it again. User.java
public class User implements java.io.Serializable {
private String name;
public User(String name) {
this.name = name;
}
@Override
public String toString() {
returnname; }} Copy the codeCopy the code
UserSerializeTest.java
public class UserSerializeTest {
public static void main(String[] args) throws Exception {
User user = new User("Code Maker's Notes.");
FileOutputStream fo = new FileOutputStream("user.bytes"); ObjectOutputStream so = new ObjectOutputStream(fo); so.writeObject(user); so.close(); }} Copy the codeCopy the code
User.java
public class User implements java.io.Serializable {
private String name;
private String desc;
public User(String name) {
this.name = name;
}
@Override
public String toString() {
returnname; }} Copy the codeCopy the code
UserDeserializeTest.java
public class UserDeserializeTest {
public static void main(String[] args) throws Exception {
FileInputStream fi = new FileInputStream("user.bytes");
ObjectInputStream si = new ObjectInputStream(fi); User user = (User) si.readObject(); System.out.println(user); si.close(); }} Copy the codeCopy the code
In the code above, we run UserSerializeTest. Java, modify user.java, add a property desc, and run the code again. Did it go wrong?
Exception in thread "main" java.io.InvalidClassException:
com.github.codedrinker.p1413.User;
local class incompatible:
stream classdesc serialVersionUID = 6360520658036414457,
localClass serialVersionUID = -3025746955499933156 Copy codeCopy the code
It shows that serialVersionUID is different, deserialization failed, but we did not define serialVersionUID why? All at the end of the source text (access) king stepped in, it is time for source code. We check the Java IO. ObjectStreamClass# writeNonProxy, if the current class (User) is not defined serialVersionUID, It invokes the Java. IO. ObjectStreamClass# computeDefaultSUID generate the default serialization only. We simply look at the code and find that its generation rule is based on the hash value generated by the class name, result, method and attribute, so we add desc attribute to User, so the corresponding serialVersionUID will definitely change.
This is explained in the JVM specification [1]
The stream-unique identifier is
a 64-bit hashof the class name, interface class names, methods, and fields. Copy the codeCopy the code
To verify this, use the JDK’s serialver tool, which uses the same rules as the JDK’s default serialVersionUID.
Serialver com. Making. Codedrinker. P1413. Copy the User codeCopy the code
You can get the serialVersionUID before and after adding desc, as shown below
Private static final Long serialVersionUID = 6360520658036414457L; Private static Final Long serialVersionUID = -3025746955499933156l; private static final Long serialVersionUID = -3025746955499933156l; Copy the codeCopy the code
Okay, so if we look at this we can fix this problem by modifying one place. Manually define a serialVersionUID code as follows user.java
public class User implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private String name;
public User(String name) {
this.name = name;
}
@Override
public String toString() {
returnname; }} Copy the codeCopy the code
Repeat the above steps to deserialize successfully.
Here we all understand why the documentation states that serialVersionUID cannot be easily changed. However, 1L at a time is not an option, so you can configure IDEA so that the prompt will be generated automatically when creating classes.
Other serialization methods
The manual only mentions the Java default serialization method, but there are many serialization methods that perform well, such as JSON or byte stream, as mentioned above, such as the popular ones: Hessian, Kryo, Fastjson, ProtoBuf, Jackson, etc., all have their advantages and disadvantages. Here are performance comparisons of JVP-Serializers [2] for limited reference in your choices.