With the Java Serializable interface, we may have the following problems

  • What are serialization and deserialization

  • The Serializable interface should be serialized

  • How is the value of serialVersionUID set? What is the use? There’s 1L, there’s a bunch of numbers, confusing ing.

When I first saw this keyword Serializable, it was like this.

Before you tackle this problem, you need to know one thing, and it’s important.

The Serializable interface, and related stuff, is all in Java IO.

1. Concepts of serialization and deserialization

  • Serialization: The process of converting an object into a sequence of bytes is called object serialization.

  • Deserialization: The process of restoring a sequence of bytes to an object is called deserialization of an object.

That’s the technical explanation. Now let’s go to the popular explanation. When the code is running, we can see many objects, which can be a single object, or a collection of objects, a lot of object data, some of the data, we want to keep it persistent, then this is called serialization.

This is the process described in converting these objects in memory into a sequence of bytes. I can save files without serializing them what does it matter? That’s what I asked.

2. When is serialization required

When you want to save the state of an object in memory to a file or database;

When you want to use a socket to send objects over the network;

When you want to transfer objects over RMI;

(To be honest, I’ve probably used one of the above.)

3. How does Java implement serialization

Implement the Serializable interface

While the above theory is fairly simple, here’s the actual code to see what serialization can do and the bugs it can cause.

So let’s start with object code, pig.java

package com.lxk.model; import java.io.Serializable; /** * @author lxk on 2017/11/1 */ public class FlyPig implements Serializable { //private static final long serialVersionUID = 1L; private static String AGE = "269"; private String name; private String color; transient private String car; //private String addTip; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public String getCar() { return car; } public void setCar(String car) { this.car = car; } //public String getAddTip() { // return addTip; //} // //public void setAddTip(String addTip) { // this.addTip = addTip; //} @Override public String toString() { return "FlyPig{" + "name='" + name + '\'' + ", color='" + color + '\'' + ", car='" + car + '\'' + ", AGE='" + AGE + '\'' + //", addTip='" + addTip + '\'' + '}'; }}Copy the code

Note that the annotated code will be used in a variety of situations later.

So here’s the main method

package com.lxk.test; import com.lxk.model.FlyPig; import java.io.*; Public class SerializableTest {public static void main(String[] args) {public static void main(String[] args) throws Exception { serializeFlyPig(); FlyPig flyPig = deserializeFlyPig(); System.out.println(flyPig.toString()); } /** * serialize */ private static void serializeFlyPig() throws IOException {FlyPig FlyPig = new FlyPig(); flyPig.setColor("black"); flyPig.setName("naruto"); flyPig.setCar("0000"); // ObjectOutputStream Outputs the object stream, and stores the flyPig object to the flyPig. TXT file in disk E. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:/ flypig.txt "))); oos.writeObject(flyPig); System.out.println("FlyPig object serialized successfully!" ); oos.close(); } /** * deserialize */ private static FlyPig deserializeFlyPig() throws Exception {ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:/flyPig.txt"))); FlyPig person = (FlyPig) ois.readObject(); System.out.println("FlyPig object deserialized successfully!" ); return person; }}Copy the code

A brief description of the above two classes that operate on file streams

ObjectOutputStream represents an ObjectOutputStream:

Its writeObject(Object OBj) method serializes the obj Object specified by the parameter, writing the resulting byte sequence to a target output stream.

ObjectInputStream represents an ObjectInputStream:

Its readObject() method reads byte sequences from a source input stream, deserializes them into an object, and returns them.

How to look at the operation.

The first way: come up with the code, do not move, directly run, see the effect.

As a result, it will generate a file in d:/ flypig.txt.

From the running results:

  • It implements object serialization and deserialization.

  • Transient attributes are not serialized. The Audi four-circle car I set up is gone. It’s null. My god.

  • Before you start, the static variable AGE is also serialized. This has to be tested separately.

Second: To verify that the static attribute can be serialized and deserialized, do the following.

    public static void main(String[] args) throws Exception {
        serializeFlyPig();
        //FlyPig flyPig = deserializeFlyPig();
        //System.out.println(flyPig.toString());
    }
Copy the code

So once you’ve done that, what it means is you serialize an object to a file. This object is static with static variables.

Now change the AGE value in flyPig to 26.

Then, look at the running code and the result below.

As you can see, 269, which was just serialized, is not read. It’s the 26 that you just modified, and if you can, it overwrites the 26, which is 269.

Therefore, it is concluded that the static property is not serialized.

Third: demonstrate the role and use of the serialVersionUID

The most violent change is to simply remove the interface implemented by the Model class. The subsequent methods of serialization and deserialization are then performed. Report an error directly.

Throw exception: NotSerializableException

It’s too violent. I don’t recommend it.

Then, again, the serialization method is executed separately. Generate files.

Then, open the property addTip, and after that, deserialize again to see what happens.

Throw exception: InvalidClassException details are as follows.

InvalidClassException: com.lxk.model.FlyPig; 
local class incompatible: 
stream classdesc serialVersionUID = -3983502914954951240, 
local class serialVersionUID = 7565838717623951575
Copy the code

Explain:

Because I did not explicitly assign a value to the serialVersionUID in the Model, Java will automatically assign a value to me, which is calculated based on the model properties.

When I saved it, when I serialized it, it didn’t have this addTip property, so the serialVersionUID value that was automatically generated by Java when I deserialized it was different, so it threw an exception.

(You can also reverse this by serializing with ID, and then deserializing with no ID. Same problem.)

Private static Final Long serialVersionUID = 1L; Comments open for this line of code. That addTip property is commented out, serialized, turned on, deserialized. Let’s see what happens.

At this point, the code executes OK and everything is fine. Good. Serialization, there is no that attribute, in the serialization of the time, the corresponding model more than a attribute, but, deserialization execution OK, no exception.

What does this phenomenon mean for us:

First of all, if you don’t know what this serialization does, in case it does save the database as mentioned in the beginning, socket transfer, RMI transfer. I don’t know what it is, though. If you do not write the serialVersionUID, you may have a bug that does not recognize old data when you extend it later. Recall the error above. It’s horrible to think about. Who’s going to carry the pot?

So, there is a theory that when implementing the Serializable interface, you must assign a value to the serialVersionUID, that’s the problem.

This explains why, when we first started coding, the Eclipse editor had to yellow alert and add the value of this ID after implementing this interface. And it’s a long list of numbers that you don’t even know how to get.

Here’s how to set the serialVersionUID value to be OK.

First of all, you don’t have to do the assignment yourself, Java will do the assignment for you, but this will cause the above bug, it is not safe, so you have to do it yourself.

So, what do I do? Eclipse will probably automatically give you a bunch of numbers. This is unnecessary.

We can simply assign 1L, and that’s it. This ensures successful deserialization when code is consistent.

Different serialVersionUID values affect deserialization, that is, reading the data, so you write 1L, note that L is bigger. Computers are case insensitive, but as viewers, we need to distinguish between 1 and L of L, so this value should not be disturbed, or a version update, the old data will not be compatible, you do not know where the problem is…

The following is a description of the interface Serializable from the JDK API documentation

Class implements the java.io.Serializable interface to enable its serialization capabilities. Classes that do not implement this interface will not be able to serialize or deserialize any of their state. All subtypes of a serializable class are themselves serializable. Because implementing interfaces is also the indirect equivalent of inheritance. The serialization interface has no methods or fields and is used only to identify serializable semantics.

Description of serialVersionUID

(Note that the two paragraphs in this screenshot are corresponding to the following two Paragraphs in Chinese. Static properties are not serialized, but there is a particular static property that is serialized, and it has to be serialized. Bring your own.

The serialization runtime is associated with each serializable class using a version number called serialVersionUID, which is used during deserialization to verify that the sender and receiver of the serialized object loaded a serialization-compatible class for the object. If the serialVersionUID of the object’s class loaded by the receiver is different from the version number of the corresponding sender’s class, deserialization will result in an InvalidClassException. Serializable classes can explicitly declare their own serialVersionUID by declaring a field named “serialVersionUID” (which must be a static, final, long field) :

If a serializable class does not explicitly declare a serialVersionUID, the serializable runtime computes the default serialVersionUID value for the class based on aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare the serialVersionUID value, because calculating the default serialVersionUID is highly sensitive to class details and can vary widely depending on compiler implementations, This can result in an unexpected InvalidClassException during deserialization.

Therefore, to ensure consistency of the serialVersionUID value across different Java compiler implementations, the serialized class must declare an explicit serialVersionUID value. It is also strongly recommended to display the declaration serialVersionUID with the private modifier, if possible, because this declaration only applies to directly declared classes — the serialVersionUID field is not useful as an inherited member. Array classes cannot declare an explicit serialVersionUID, so they always have a default computed value, but the array class does not match the requirement for a serialVersionUID value.

Write in the last

Welcome to pay attention to my public number [calm as code], massive Java related articles, learning materials will be updated in it, sorting out the data will be placed in it.

If you think it’s written well, click a “like” and add a follow! Point attention, do not get lost, continue to update!!