preface
Java object “implements Serializable” So, what does it do? This paper analyzes the sequence from the following points of view
- What is Java serialization?
- Why serialization?
- Serialization purpose
- Common APIS for Java serialization
- Use of serialization
- Serialization layer
- Daily development of serialization considerations
- Serialization is common
What is Java serialization?
- Serialization: The process of converting Java objects into byte sequences
- Antisequence: The process of restoring a sequence of bytes to Java objects
Why serialization?
Java objects run in the JVM’s heap memory, and their lives come to a screeching halt when the JVM stops.
Metaphorically, as a wandering yard farmer in a big city, moving is the norm. When we move a desk, it’s too big to fit through a smaller door, so we have to take it apart and move it through, and the process of taking it apart is called serialization. The process of putting the desk back together is deserialization.
Serialization purpose
Serialization allows objects to exist independently of the program and serves two main purposes:
- 1) Serialization mechanism allows objects to be stored on hard disk, reducing memory pressure and playing a role of persistence;
For example, the Session object in the Web server, when there are more than 100,000 concurrent users access, there may be 100,000 Session objects, memory may indigestion, so the Web container will first serialize some Seesion to the hard disk, and then restore the objects saved in the hard disk to the memory when they need to use.
- 2) Serialization mechanism makes it possible for Java objects to be transported over the network.
When we use Dubbo to call the service framework remotely, we need to implement the Serializable interface for the transferred Java objects, so that the objects can be transferred over the network.
Java serialization API
java.io.ObjectOutputStream
java.io.ObjectInputStream
java.io.Serializable
java.io.Externalizable
Copy the code
The Serializable interface
The Serializable interface is a tag interface with no methods or fields. Once this interface is implemented, objects of that class are signaled to be serializable.
public interface Serializable {
}
Copy the code
Externalizable interface
Externalizable inherits the Serializable interface and defines two abstract methods: WriteExternal () and readExternal(). If a developer uses Externalizable for serialization and deserialization, the writeExternal() and readExternal() methods need to be overridden
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
Copy the code
Java. IO. ObjectOutputStream classes
Represents an Object output stream, whose writeObject(Object obj) method serializes the specified OBj Object parameters and writes the resulting byte sequence to a target output stream.
java.io.ObjectInputStream
Represents an object input stream, whose readObject() method reads a sequence of bytes from the input stream, deserializes it into an object, and finally returns it.
Use of serialization
How is serialization used? Let’s take a look at some key aspects of serialization:
- Declare an entity class that implements the Serializable interface
- The writeObject method of ObjectOutputStream is used to achieve serialization
- Deserialization is implemented using ObjectInputStream’s readObject method
Declare a Student class that implements Serializable
public class Student implements Serializable {
private Integer age;
private String name;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) { this.name = name; }}Copy the code
Serialize the Student object using the writeObject method of the ObjectOutputStream class
Serialize the Student object to a file
ObjectOutputStream objectOutputStream = new ObjectOutputStream( new FileOutputStream("D:\\text.out"));
Student student = new Student();
student.setAge(25);
student.setName("jayWei");
objectOutputStream.writeObject(student);
objectOutputStream.flush();
objectOutputStream.close();
Copy the code
The test.out file looks like this:
Use ObjectInputStream’s readObject method to deserialize and regenerate the Student object
Read the test.out file and deserialize it into the Student object
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\text.out"));
Student student = (Student) objectInputStream.readObject();
System.out.println("name="+student.getName());
Copy the code
Serialization layer
The Serializable underlying
Serializable interface is an empty interface with no methods or fields.
public interface Serializable {
}
Copy the code
To verify the Serializable interface, remove the Student object from the above demo and see how Serializable can be serialized
An exception was raised during serialization.
Exception in thread "main" java.io.NotSerializableException: com.example.demo.Student
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.example.demo.Test.main(Test.java:13)
Copy the code
Take a look at the stack of information, the original significant discovery, as follows ~
The bottom layer looks like this:
Serializable is really just a flag, a serialization flag
WriteObject (Object)
The serialization method is writeObject. Based on the above demo, we will analyze the core method call chain of writeObject.
WriteObject directly calls the writeObject0 () method,
public final void writeObject(Object obj) throws IOException {
......
writeObject0(obj, false); . }Copy the code
The main implementation of writeObject0 is different types of objects, which call different methods to write serialized data. In this case, if the object implements the Serializable interface, the writeOrdinaryObject() method ~ is called
private void writeObject0(Object obj, boolean unshared) throws IOException { ...... / / type Stringif(obj instanceof String) { writeString((String) obj, unshared); // Array type}else if(cl.isArray()) { writeArray(obj, desc, unshared); // Enumeration type}else if(obj instanceof Enum) { writeEnum((Enum<? >) obj, desc, unshared); //Serializable implements serialization interface}else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);
} else{// Other cases throw exceptions ~if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "\n" + debugInfoStack.toString());
} else{ throw new NotSerializableException(cl.getName()); }}...Copy the code
WriteOrdinaryObject () calls writeClassDesc(desc) to write the class’s generated information, and then calls the writeSerialData method to write serialized data
private void writeOrdinaryObject(Object obj, ObjectStreamClass desc, boolean unshared) throws IOException { ...... // Call ObjectStreamClass writeClassDesc(desc,false); // Check whether the Externalizable interface is implementedif(desc.isExternalizable() && ! desc.isProxy()) { writeExternalData((Externalizable) obj); }else{// Write serialized data writeSerialData(obj, desc); }... }Copy the code
WriteSerialData () implements writing field data to the serialized object
private void writeSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
for (int i = 0; i < slots.length; i++) {
if(slotDesc hasWriteObjectMethod ()) {/ / if the serialized objects custom implements writeObject () method, execute the code block slotDesc. InvokeWriteObject (obj, this); }else{// Call the default method to write instance data defaultWriteFields(obj, slotDesc); }}}Copy the code
DefaultWriteFields () gets the basic data type of the class and writes it directly to the underlying byte container; Get the obJ data of the class, loop recursively call writeObject0(), write data ~
Private void defaultWriteFields(Object obj, ObjectStreamClass desc) throws IOException {// Get the basic data type of the class. Save to primVals byte array desc.getPrimfieldValues (obj, primfieldValues); Bout. Write (primVals, 0, primDataSize,false); ObjectStreamField[] fields = desc. GetFields (ObjectStreamField[] fields = desc.false); Object[] objVals = new Object[desc.getNumObjFields()]; int numPrimFields = fields.length - objVals.length; GetObjFieldValues (obj, objJ); // Get the values of type OBj and save them to objVals byte array desc.getObjFieldValues(obj, objJ); // For all fields of type Object, loopfor(int i = 0; i < objVals.length; i++) { ...... WriteObject0 (objprimfields [I], fields[numPrimFields + I].isunshared ()); . }}Copy the code
7. Some considerations for daily development of serialization
- Static static variables and transient modified fields are not serialized
- SerialVersionUID problem
- If the member variable of a serialized class is an object type, the class of that object type must implement serialization
- The subclass realizes serialization, the parent class does not realize serialization, and the field loss problem in the parent class
Static static variables and transient modified fields are not serialized
Class gender (gender); class specialty (gender)
public class Student implements Serializable {
private Integer age;
private String name;
public static String gender = "Male";
transient String specialty = "Computer science";
public String getSpecialty() {
return specialty;
}
public void setSpecialty(String specialty) {
this.specialty = specialty;
}
@Override
public String toString() {
return "Student{" +"age=" + age + ", name='" + name + '\'' + ", gender='" + gender + '\'' + ", specialty='" + specialty + '\' ' +
'} '; }...Copy the code
Print the student object, serialize it to a file, then modify the value of the static variable, deserialize again, and output the deserialized object ~
Student{age=25, name='jayWei', gender='male', specialty='Computer Science'} Student{age=25, name='jayWei', gender='woman', specialty='null'}
Copy the code
The comparison results can be found:
- 1) The gender of the static variable before serialization was clearly “male”, and then changed in the program after serialization, but changed to “female” after deserialization, what? It is obvious that this static property has not been serialized. Static member variables are class-level variables, and serialization is for objects.
- 2) After the serialization and deserialization process, the value of the specialty field variable from ‘computer major’ becomes null. The transient keyword prevents the transient field from being serialized to the file. After deserialization, the transient field value is set to the initial value, for example, the int value is set to 0, and the object value is set to NULL.
SerialVersionUID problem
SerialVersionUID Every class that implements the Serializable interface has a static variable representing the Serializable version identifier, either equal to 1L by default or equal to the object’s hash code.
private static final long serialVersionUID = -6384871967268653799L;
Copy the code
What is the use of serialVersionUID?
The mechanism for JAVA serialization is to verify version consistency by determining the serialVersionUID of a class. When deserializing, the JVM compares the serialVersionUID in the incoming byte stream with the serialVersionUID of the corresponding local entity class. If they are the same, the deserialization succeeds. If they are different, an InvalidClassException is thrown.
Next, let’s verify by modifying the Student class and deserializing the operation
Exception in thread "main" java.io.InvalidClassException: com.example.demo.Student;
local class incompatible: stream classdesc serialVersionUID = 3096644667492403394,
local class serialVersionUID = 4429793331949928814
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1876)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1745)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2033)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at com.example.demo.Test.main(Test.java:20)
Copy the code
As you can see from the log stack exception information, the class in the file stream is different from the class in the current classpath. Their serialVersionUID is different, so deserialization throws an InvalidClassException. So what if you do need to modify the Student class, and you want to deserialize successfully? You can specify the value of serialVersionUID manually, typically set to 1L or, alternatively, let our editor IDE generate it
private static final long serialVersionUID = -6564022808907262054L;
Copy the code
In fact, Ali’s development manual mandates that the serialVersionUID field ~ cannot be modified when new attributes are added to serialized classes
If the member variable of a serialized class is an object type, the class of that object type must implement serialization
Add a Teacher member variable to the Student class, where Teacher does not implement the serialization interface
public class Student implements Serializable { private Integer age; private String name; private Teacher teacher; . } //Teacher does not implement public class Teacher {...... }Copy the code
Serializableexception NotSerializableException
Exception in thread "main" java.io.NotSerializableException: com.example.demo.Teacher
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.example.demo.Test.main(Test.java:16)
Copy the code
This can be found in the underlying source code analysis in the previous section. An Object serialization process will loop through its Object field and recursively call the serialized class. That is, when serializing Student, it will serialize Teacher, but there is no serialization interface implemented for Teacher. Therefore, NotSerializableException is thrown. So if the member variable of an instantiated class is an object type, the class of that object type must implement serialization
If a subclass implements Serializable, its parent class does not implement the Serializable interface.
The subclass Student implements the Serializable interface, while the parent class User does not
Public class Student extends User implements Serializable {private Integer age; private String name; } // Serializable interface public class User {String userId; } Student student = new Student(); student.setAge(25); student.setName("jayWei");
student.setUserId("1");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\text.out")); objectOutputStream.writeObject(student); objectOutputStream.flush(); objectOutputStream.close(); ObjectInputStream ObjectInputStream = new ObjectInputStream(new FileInputStream("D:\\text.out"));
Student student1 = (Student) objectInputStream.readObject();
System.out.println(student1.getUserId());
//output
/**
* null
*/
Copy the code
From the deserialization results, you can see that the parent class attribute value is missing. Therefore, a subclass implements the Serializable interface. If the parent class does not implement the Serializable interface, the parent class is not serialized.
Serialization often meet test questions
- How does serialization work at the bottom?
- When serializing, how do I keep some members from being serialized?
- What is the difference between Serializable and Externalizable in Java
- What is the use of serialVersionUID?
- Can you customize the serialization process, or can you override the default serialization process in Java?
- What variables are not serialized during Java serialization?
1. How is serialization implemented at the bottom?
The Serializable keyword can also be used to write basic types directly, obtain obJ data, and loop recursively to writeObject
2. When serializing, how to make certain members not serialized?
The transient keyword can be used to prevent the modified field from being serialized to the file. After deserialization, the transient field value is set to the initial value, for example, the int value will be set to 0, and the object value will be set to NULL.
3. What is the difference between Serializable and Externalizable in Java
Externalizable inherits Serializable, giving us the writeExternal() and readExternal() methods that allow us to control Java’s serialization mechanism without relying on Java’s default serialization. Properly implementing the Externalizable interface can significantly improve application performance.
4. What does serialVersionUID do?
As you can see in section 7 of this article, the mechanism for JAVA serialization is to verify version consistency by determining the serialVersionUID of a class. When deserializing, the JVM compares the serialVersionUID in the incoming byte stream with the serialVersionUID of the corresponding local entity class. If they are the same, the deserialization succeeds. If they are different, an InvalidClassException is thrown.
5. Can you customize the serialization process, or can you override the default serialization process in Java?
You can. As we all know, to serialize an object to call the ObjectOutputStream. WriteObject (saveThisObject), and the ObjectInputStream. ReadObject () reads the object, But one more thing that the Java VIRTUAL machine gives you is to define these two methods. If these two methods are defined in a class, the JVM calls them instead of applying the default serialization mechanism. At the same time, you can declare these methods private to avoid being inherited, overridden, or overridden.
6. Which variables were not serialized during Java serialization?
Static static variables and transient modified fields are not serialized. Static member variables are class-level, whereas serialization is for objects. The TRANSIENT keyword modifies the field ornament to prevent the field from being serialized to the file.
Reference and thanks
- Java Basics – Serialization and deserialization of Java objects
- 10 Tough Java Interview Questions and Answers
Personal public account
- If you think it’s good, give me a thumbs up and attention. Thank you
- If there is any incorrect place, please kindly point out, thank you very much.
- At the same time, I am looking forward to friends can pay attention to my public account, behind slowly launch better dry goods ~ hee hee
-
- Github address: github.com/whx123/Java…