Serializable details: code validation Java serialization and deserialization

Keywords: Programming Java SpringBoot Attribute network

Note: This paper is a detailed explanation of Serializable (1). The last two paragraphs are ambiguous in translation (not translated for the time being), which will be supplemented in subsequent Serializable (2).

Introduction: This article is translated according to JDK English document. This translation is not completely literal translation according to the original document, but is translated into clearer and easier to understand text combined with document content and personal experience, and code verification is added to help you better understand Serializable.

Nature: Interface

package java.io

public interface Serializable

###1.1 translation of documents

Serializability of a class is enabled by the class implementing the java.io.Serializable interface.

Serialize a class by implementing the java.io.Serializable interface interface.

Classes that do not implement this interface will not have any of their state serialized or deserialized.
 
Any state of a class that does not implement this interface will not be serialized or deserialized.
    
All subtypes of a serializable class are themselves serializable.

All subclasses of a serializable class are themselves serializable.
    

The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
 
//The serialization interface has no method or field fields, it is only used to identify serializable semantics.
    
(1)To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields. 

(2)The subtype may assume this responsibility only if the class it extends has an accessible no-arg constructor to initialize the class's state.  It is an error to declare a class Serializable if this is not the case.  The error will be detected at runtime.

(3)During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class.  A no-arg constructor must be accessible to the subclass that is serializable.  The fields of serializable subclasses will be restored from the stream.

(1) In order to make the subclass of the non serialized class serializable, this subclass can undertake to save and recover the pulic, protected and package fields of the superclass (if accessible).

(2) Only when the class it extends has an accessible parameterless constructor to initialize the state of the class, can the subclass assume such responsibility. If this is not the case, a class cannot be declared serializable. This error will be detected at runtime.

(3) During deserialization, the fields of the non serialized class are instantiated through the class's empty parameter constructor decorated with public or protected. Parameterless constructors must have access to serializable subclasses. The fields of the serialized subclass can be restored from the character stream.
    
###1.2 auxiliary understanding

(1) (2) (3) there are three things in three parts:

-For the non serialized parent class, its subclass is responsible for saving and recovering the fields that can be accessed by subclasses such as public, protected, package, etc;
-For a non serialized parent class, when its children are serialized, the parent class needs a null parameter constructor decorated with public or protected;
-If there is no parent class of null parameter constructor, its child class will run normally during serialization, but an error will occur during deserialization and an exception will be thrown. But the parent class has an empty parameter constructor, and the child class completes the serialization, but the parent class property does not participate in the serialization.
    
###1.3 note: there are three pits here.

-(1) The parent class described in does not implement serialization. The child class that implements serialization will assume that the child classes such as public, protected, package and so on can access the fields of the child class. Here I personally understand that the subclass that implements serialization inherits the properties that can be accessed by the subclass of the parent class that does not implement serialization, but the state information of the parent class object cannot be recorded during serialization;
-If you want to read and understand the document correctly, remember that (1) (2) (3) cannot be separated and should be put together to understand (the reason why the above separation is convenient for translation);
-It's difficult to understand the real meaning of the Chinese characters in English translation, so the following code verification is used to assist understanding
   
###1.4 code verification

Supplemented by A/B two sets of type code comparative understanding:

####1) A set
        
Parent class: Biology class

package com.springboot.SpringBootDemo.serializable;  
      
            public class Biology {  
                  
                public String type;  
                  
                private int num;  
              
                public Biology(String type, int num) {  
                    this.type = type;  
                    this.num = num;  
                }  
              
                public String getType() {  
                    return type;  
                }  
              
                public void setType(String type) {  
                    this.type = type;  
                }  
              
                public int getNum() {  
                    return num;  
                }  
              
                public void setNum(int num) {  
                    this.num = num;  
                }  
            }  

Subclass: People class
      

package com.springboot.SpringBootDemo.serializable;  
      
            import java.io.Serializable;  
              
            public class People extends Biology implements Serializable{  
              
                private static final long serialVersionUID = -6623611040000763479L;  
              
                public String name;  
                  
                protected String gender;  
                  
                private int age;  
              
                public People(String type, int num, String name ,String gender ,int age) {  
                    super(type, num);  
                    this.name = name;  
                    this.gender = gender;  
                    this.age = age;  
                }  
              
                public String getName() {  
                    return name;  
                }  
              
                public void setName(String name) {  
                    this.name = name;  
                }  
              
                public String getGender() {  
                    return gender;  
                }  
              
                public void setGender(String gender) {  
                    this.gender = gender;  
                }  
              
                public int getAge() {  
                    return age;  
                }  
              
                public void setAge(int age) {  
                    this.age = age;  
                }  
            }  

Test class:
           

           import java.io.FileInputStream;  
            import java.io.FileOutputStream;  
            import java.io.IOException;  
            import java.io.ObjectInputStream;  
            import java.io.ObjectOutputStream;  
              
            public class Test {  
                  
                public static void main(String\[\] args) throws IOException, ClassNotFoundException {  
                    People pp = new People("human",10000,"Zhang San","male",25);  
                      
                    FileOutputStream fos = new FileOutputStream("test.txt");  
                    ObjectOutputStream oos = new ObjectOutputStream(fos);  
                    oos.writeObject(pp);  
                    oos.flush();  
                    oos.close();  
                      
                    //De serialization  
                    FileInputStream sfis = new FileInputStream("test.txt");  
                    ObjectInputStream sois = new ObjectInputStream(sfis);  
                    People p = (People) sois.readObject();  
                    System.out.println(  
                            p.getType() +" "+  
                            p.getNum() +" "+  
                            p.getName() +" "+  
                            p.getGender() +" "+  
                            p.getAge()  
                            );  
                }  
            }  

Result:

   Exception in thread "main" java.io.InvalidClassException: com.springboot.SpringBootDemo.serializable.People; no valid constructor  
                at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(Unknown Source)  
                at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)  
                at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)  
                at java.io.ObjectInputStream.readObject0(Unknown Source)  
                at java.io.ObjectInputStream.readObject(Unknown Source)  
                at com.springboot.SpringBootDemo.serializable.Test.main(Test.java:23)  
```                

The result shows that there is no exception in serialization, but an exception in deserialization of readObject(). That is to say, when the parent class does not have a parameterless constructor, serialization works normally, but a newInvalidClassException exception is thrown during deserialization.  
    
\####2) set B

Parent class: Person class

            public class Person {
                
                public String name;
                
                public String gender;
                
                public int age;
                
                float height;
                
            
                public String getName() {
                    return name;
                }
            
                public void setName(String name) {
                    this.name = name;
                }
            
                public String getGender() {
                    return gender;
                }
            
                public void setGender(String gender) {
                    this.gender = gender;
                }
            
                public int getAge() {
                    return age;
                }
            
                public void setAge(int age) {
                    this.age = age;
                }
            
                public float getHeight() {
                    return height;
                }
            
                public void setHeight(float height) {
                    this.height = height;
                }
            }

Subclass: Male  
    

        import java.io.Serializable;
        
        public class Male extends Person implements Serializable{
            /**
             * 
             */
            private static final long serialVersionUID = -7361904256653535728L;
            
            public boolean beard;
            
            protected String weight;
            
        
            public boolean havaBeard(int age){
                boolean flag = false;
                
                if(age>=18){
                    flag = true;
                }
                return flag;
            }
        
        
            public boolean isBeard() {
                return beard;
            }
        
        
            public void setBeard(boolean beard) {
                this.beard = beard;
            }
        
        
            public String getWeight() {
                return weight;
            }
        
        
            public void setWeight(String weight) {
                this.weight = weight;
            }
            
        }

          
Test class:  
    

        import java.io.FileInputStream;
        import java.io.FileOutputStream;
        import java.io.IOException;
        import java.io.ObjectInputStream;
        import java.io.ObjectOutputStream;

        public class SubTypeSerializable {
        
            public static void main(String[] args) throws IOException, ClassNotFoundException{
                
/ * * Male inherits the parent class Person and implements the serialization interface itself. The parent class Person does not implement the serialization interface*/
                FileOutputStream fos = new FileOutputStream("male.txt");
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                Male male = new Male();
                /**
* properties of Person, the parent of its parent
                 * 
                 * public String name;
                   public String gender;
                   public int age;
                   float height;
                 * /
male.setName("Zhang San");
male.setGender("male");
                male.setAge(25);
                male.setHeight(175);
                /*
* its own properties
                 * public boolean beard;
                 * */
                male.setBeard(true);
                oos.writeObject(male);
                oos.flush();
                oos.close();
                
/ / deserialization
                FileInputStream fis = new FileInputStream("male.txt");
                ObjectInputStream ois = new ObjectInputStream(fis);
                Male ml = (Male) ois.readObject();
                System.out.println(ml.getName() +" "+ml.getGender()+" "+ml.getHeight() +" "+ml.getAge()+" "+male.isBeard());
              }
    }          


//Result:

```     
    ml.getName() == null   
    ml.getGender() == null   
    ml.getHeight() == 0.0   
    ml.getAge() == 0   
    male.isBeard() == true  

    
###1.5 test analysis

####1) parent property

public String name;

public String gender;

public int age;

float height;
   
The status information has not been recorded;
   
####2) own attributes

public boolean beard;

Its status information is recorded

###2.1 translation of documents

When traversing a graph, an object may be encountered that does not support the Serializable interface. In this case the NotSerializableException will be thrown and will identify the class of the non-serializable object.

When looping through a data structure graph (data structure graph can be understood as data structure type, such as binary tree), the object may encounter a situation that does not support the implementation of serialization interface. In this case, a NotSerializableException exception is thrown and the class is defined as a non serializable class.
    

Classes that require special handling during the serialization and deserialization process must implement special methods with these exact signatures:

During the implementation of serialization and deserialization, special processing classes need to implement these special methods:

   private void writeObject(java.io.ObjectOutputStream out) throws IOException

   private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;   
                             
   private void readObjectNoData() throws ObjectStreamException;  
``` 

>The writeObject method is responsible for writing the state of the object for its particular class so that the corresponding readObject method can restore it.  The default mechanism for saving the Object's fields can be invoked by calling out.defaultWriteObject. The method does not need to concern itself with the state belonging to its superclasses or subclasses. State is saved by writing the individual fields to the ObjectOutputStream using the writeObject method or by using the methods for primitive data types supported by DataOutput.

witeObject Method is responsible for writing the Object Object status information, readObject Method can restore the Object Object status information. Save this Object The default mechanism for object fields is by calling out.defaultWriteObject To achieve. This method does not need to pay attention to the state belonging to its superclass or subclass. through the use of writeObject Method to write each field ObjectOutputStream,Or use DataOutput Supported methods for basic data types to save state.  
                                                                                 
>The readObject method is responsible for reading from the stream and restoring the classes fields. It may call in.defaultReadObject to invoke the default mechanism for restoring the object's non-static and non-transient fields.  The defaultReadObject method uses information in the stream to assign the fields of the object saved in the stream with the correspondingly named fields in the current object.  This handles the case  when the class has evolved to add new fields. The method does not need to  concern itself with the state belonging to its superclasses or subclasses. State is saved by writing the individual fields to the ObjectOutputStream using the writeObject method or by using the methods for primitive data types supported by DataOutput.

readObject Method is responsible for reading the data stream and recovering the fields of the class. It can be called in.defaultReadObject To restore non static And non transient Decorated field. defaultReadObject Method through the information in the data flow, the field information of the current class saved in the data flow is assigned to the corresponding field name (that is, the value of the field is assigned to the corresponding field name). This processing method can also handle the new fields of this type. This method does not need to pay attention to the state belonging to its superclass or subclass. through the use of writeObject Method to write each field ObjectOutputStream,Or use DataOutput Supported methods for basic data types to save state. adopt writeObject Method object Object Each field of is written to ObjectOutputStream Or by using DataOutput Supported methods of basic data types to save the Object Object status information.  
                                                                                 
>The readObjectNoData method is responsible for initializing the state of the object for its particular class in the event that the serialization stream does not list the given class as a superclass of the object being deserialized.  This may occur in cases where the receiving party uses a different version of the deserialized instance's class than the sending party, and the receiver's version extends classes that are not extended by the sender's version.  This may also occur if the serialization stream has been tampered; hence, readObjectNoData is useful for initializing deserialized objects properly despite a "hostile" or incomplete source stream.

(Translation there is a little hard work, so direct software translation will be followed by code verification and understanding)

//The readObjectNoData() label method is responsible for initializing the field values of an object when there is a discrepancy between the deserialization and the version of the serialized class. This may happen when deserializing, the receiver uses different versions of the class of the sender object, or the version of the class inherited by the receiver is not the same as the version of the class inherited by the sender. In addition, this happens when the serialization stream is tampered with. Therefore, readObjectNoData is very useful to initialize the fields of the deserialized object in case of class inconsistency or incomplete deserialization flow.

\### 2.2 code verification

\#### 1) Before change

```     
    public class Cat implements Serializable{  
        /**  
         *   
         */  
        private static final long serialVersionUID = -5731096200028489933L;  
          
          
        public String color;  
          
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
        }  
    }  

    
Test class before change:

    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
    import java.io.ObjectInputStream;  
    import java.io.ObjectOutputStream;  
      
    public class CatFamilylTest {  
          
        public static void main(String\[\] args) throws Exception {  
            serializable();  
            deSerializable();  
        }  
          
        public static void serializable() throws Exception{  
            Cat cat = new Cat();  
            cat.setColor("white");  
            FileOutputStream fos = new FileOutputStream("catFamily.txt");  
            ObjectOutputStream oos = new ObjectOutputStream(fos);  
            oos.writeObject(cat);  
            oos.flush();  
            oos.close();  
        }  
          
        public static void deSerializable() throws Exception{  
            FileInputStream sfis = new FileInputStream("catFamily.txt");  
            ObjectInputStream sois = new ObjectInputStream(sfis);  
            Cat cat = (Cat) sois.readObject();  
            System.out.println(cat.getColor());  
        }  
    }  

Result: white
    
####2) first change
    
Add parent class for the first change:

    import java.io.Serializable;

    public class CatFamily implements Serializable{  
          
        /**  
         *   
         */  
        private static final long serialVersionUID = -7796480232179180594L;  
        public String catType;  
          
      
        public String getCatType() {  
            return catType;  
        }  
      
        public void setCatType(String catType) {  
            this.catType = catType;  
        }  
          
      
        private void readObjectNoData() {  
            this.catType = "tiger";                   
        }   
    }  

    
Cat changes after the first change:

    public class Cat extends CatFamily{  
        /**  
         *   
         */  
        private static final long serialVersionUID = -5731096200028489933L;  
          
          
        public String color;  
          
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
        }  
    }  

    
Read the existing catFamily.txt file for the first change:

    public class CatFamilylTest {  
      
        public static void main(String\[\] args) throws Exception {  
            deSerializable();  
        }  
        public static void deSerializable() throws Exception{  
            FileInputStream sfis = new FileInputStream("catFamily.txt");  
            ObjectInputStream sois = new ObjectInputStream(sfis);  
            Cat cat = (Cat) sois.readObject();  
            System.out.println(cat.getColor()+" <---->"+cat.getCatType());  
        }  
    }  

The result of the first change: white < --- > tiger
    
####3) second change test
    
The father of the second change:

    public class CatFamily{  
      
        public String catType;  
          
      
        public String getCatType() {  
            return catType;  
        }  
      
        public void setCatType(String catType) {  
            this.catType = catType;  
        }  
          
      
        private void readObjectNoData() {  
            this.catType = "tiger";                   
        }   
    }  
```    

//Cat category changed for the second time:

```      
    import java.io.Serializable;

    public class Cat extends CatFamily implements Serializable{  
        /**  
         *   
         */  
        private static final long serialVersionUID = -5731096200028489933L;  
          
          
        public String color;  
          
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
        }  
    }  

    
Test category changed for the second time:

    public class CatFamilylTest {  
      
        public static void main(String\[\] args) throws Exception {  
            deSerializable();  
              
        }  
        public static void deSerializable() throws Exception{  
            FileInputStream sfis = new FileInputStream("catFamily.txt");  
            ObjectInputStream sois = new ObjectInputStream(sfis);  
            Cat cat = (Cat) sois.readObject();  
            System.out.println(cat.getColor()+" <---->"+cat.getCatType());  
        }  
    }  

 
The result of the second change: white < --- > null
    
####4) comparison and verification of the third change example
    
The third change discards the parent class, and Cat class changes:

    import java.io.Serializable;

    public class Cat implements Serializable{  
        /**  
         *   
         */  
        private static final long serialVersionUID = -5731096200028489933L;  
          
        public String type;  
          
        public String color;  
          
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
        }  
          
        public String getType() {  
            return type;  
        }  
      
        public void setType(String type) {  
            this.type = type;  
        }  
      
        private void readObjectNoData() {  
            this.type = "hellokitty";                   
        }  
    }  

    
Test category changed for the third time:

    public class CatFamilylTest {  
      
        public static void main(String\[\] args) throws Exception {  
            deSerializable();  
        }  
          
        public static void deSerializable() throws Exception{  
            FileInputStream sfis = new FileInputStream("catFamily.txt");  
            ObjectInputStream sois = new ObjectInputStream(sfis);  
            Cat cat = (Cat) sois.readObject();  
            System.out.println(cat.getColor()+" <---->"+cat.getType());  
        }  
    }  

    
Test result of the third change: white < --- > null
    

###2.3 test code description
  
####1) the first type (before change)

Description: establish the Cat class that implements the serialization interface and the corresponding test class production file catFamily.txt

Two purposes:

-Basic layer code used to build changes;
-Generate the serialized file.

Results: deserialize the catFamily.txt file and get the normal result write.
       
####2) the second type (the first change and the comparison are unchanged)

Changes:

-Add the CatFamily class, which implements the serialization interface, the readObjectNoData() method, and set the attribute field catType value to tiger;
-Cat class does not directly implement Serializable interface, but inherits CatFamily class;
-The test class deserializes the catFamily.txt.

Objective: to verify the result of the readObjectNoData() label method.

Results: deserialize the catFamily.txt file and get the result white < --- > tiger.

Summary: implements the readObjectNoData() tag method.

####3) the third type (the second change compared with the first change)

Changes:

-Change the parent CatFamily class and remove the Serializable interface;
-The subclass Cat class still inherits the parent CatFamily class and directly implements the Serializable interface;
-The test class deserializes the catFamily.txt.

Purpose: to verify that the readObjectNoData() method continues to be valid when the parent class does not implement the Serializable interface.

Results: deserialize the catFamily.txt file and get the result white < --- > null.

Summary: the readObjectNoData() method is not implemented.
        
####4) the fourth type (the third change and comparison have not changed)

Changes:

-Cat class removes the parent CatFamily class and directly implements Serializable interface;
-Cat class implements readObjectNoData() method;
-The test class deserializes the catFamily.txt.

Objective: to test the scope of the readObjectNoData() method.

Results: deserialize the catFamily.txt file and get the result white < --- > null.

Summary: the readObjectNoData() method scope is to serialize the parent class of the Serializable interface for the implementation of the entity class of the Object written to the catFamily.txt file.
        
###2.4 speculative summary:

-The readObjectNoData() tag method scope is the parent class of the serialized object, and its parent class must implement the Serializable interface;
-The readObjectNoData() tag method is similar to the set attribute in the code tested above;
-The property value of the set in the readObjectNoData() label method is the property value of the class, which means that the method is invalid when referencing other object property values for set.
            
###3.1 translation of documents

Serializable classes that need to designate an alternative object to be used when writing an object to the stream should implement this special method with the exact signature:ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

When an Object object Object of a class that implements serialization is specified to be replaced by another Object that implements serialization other than this class, when writing the entity Object object to the data stream, the special label method of Object writeReplace() throws ObjectStreamException needs to be implemented.
    
###3.2 code verification

Note: both the replacement class and the replaced class need to implement the serialization interface. Otherwise, the java.io.NotSerializableException exception will be thrown when writing the writeObject, and the replaced class will be completely replaced.

####1) test writeReplace() label method

Entity class:

    import java.io.ObjectStreamException;  
    import java.io.Serializable;  
      
    public class Dog implements Serializable{  
        /**  
         *   
         */  
        private static final long serialVersionUID = -4094903168892128473L;  
          
        private String type;  
          
        private String color;  
      
        public String getType() {  
            return type;  
        }  
      
        public void setType(String type) {  
            this.type = type;  
        }  
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
        }  
        private Object writeReplace() throws ObjectStreamException {  
            Wolf wolf = new Wolf();  
            wolf.setType(type);  
            wolf.setColor(color);  
            return wolf;  
        }  
    }  
      
    class Wolf implements Serializable{  
        /**  
         *   
         */  
        private static final long serialVersionUID = -1501152003733531169L;  
      
        private String type;  
          
        private String color;  
      
        public String getType() {  
            return type;  
        }  
      
        public void setType(String type) {  
            this.type = type;  
        }  
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
        }  
    }  

    
Test class:

    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
    import java.io.IOException;  
    import java.io.ObjectInputStream;  
    import java.io.ObjectOutputStream;  
      
    public class DogTest {  
          
        public static void serializable() throws IOException{  
            Dog dog = new Dog();  
            dog.setColor("white");  
            dog.setType("Chinese garden dog");  
            FileOutputStream fos = new FileOutputStream("dog.txt");  
            ObjectOutputStream oos = new ObjectOutputStream(fos);  
            oos.writeObject(dog);  
            oos.flush();  
            oos.close();  
        }  
          
        public static void deSerializable() throws IOException,ClassNotFoundException{  
            FileInputStream sfis = new FileInputStream("dog.txt");  
            ObjectInputStream sois = new ObjectInputStream(sfis);  
            Wolf wolf = (Wolf) sois.readObject();  
            System.out.println(wolf.getType() +"<------->"+ wolf.getColor());  
        }  
          
        public static void main(String\[\] args) throws IOException ,ClassNotFoundException{  
            serializable();  
            deSerializable();  
        }  
    }  

    
Code implementation result: Chinese garden dog < ------- > white.

####2) whether the test is completely replaced

Code Description: the entity class is not modified, only the deserialization method of the test class is modified. When the readObject() method is used, it is changed from a Wolf object to a Dog object.

    public static void deSerializable() throws IOException,ClassNotFoundException{  
        FileInputStream sfis = new FileInputStream("dog.txt");  
        ObjectInputStream sois = new ObjectInputStream(sfis);  
        Dog dog = (Dog) sois.readObject();  
        System.out.println(dog.getType() +"<------->"+ dog.getColor());  
    }  

    
Code implementation result:

        (  
          //Line 25: Dog dog = (Dog) sois.readObject()  
          //Line 32: deSerializable();  
         )  
        Exception in thread "main" java.lang.ClassCastException: com.springboot.SpringBootDemo.serializable.Wolf cannot be cast to com.springboot.SpringBootDemo.serializable.Dog  
    at com.springboot.SpringBootDemo.serializable.DogTest.deSerializable(DogTest.java:25)  
    at com.springboot.SpringBootDemo.serializable.DogTest.main(DogTest.java:32)  

    
The serialized object is a Dog object, while the deserialization still passes through the Dog object, resulting in an exception. At this time, it can be seen that the Dog object is replaced by the Wolf object during serialization.

###4.1 translation of documents
        

This writeReplace method is invoked by serialization if the method exists and it would be accessible from a method defined within the class of the object being serialized. Thus, the method can have private,protected and package-private access. Subclass access to this method follows java accessibility rules.

When serializing an object, if there is a writeReplace label method in its class's method, the label method will be called when serializing the write. So this method can have private,protected and package private access. Subclasses of this class follow java accessibility rules when accessing this method.
    
###4.2 code verification

Be careful:

-The parent class implements the writeReplace tag method;
-The subclass has access to the writeReplace label method.

####1) entity class

    import java.io.ObjectStreamException;  
    import java.io.Serializable;  
      
    public class Dog implements Serializable{  
        /**  
         *   
         */  
        private static final long serialVersionUID = -4094903168892128473L;  
          
        private String type;  
          
        private String color;  
      
        public String getType() {  
            return type;  
        }  
      
        public void setType(String type) {  
            this.type = type;  
        }  
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
        }  
        public Object writeReplace() throws ObjectStreamException {  
            Wolf wolf = new Wolf();  
            wolf.setType(type);  
            wolf.setColor(color);  
            return wolf;  
        }  
    }  
      
    class ChineseGardenDog extends Dog {  
        private float height;  
      
        public float getHeight() {  
            return height;  
        }  
      
        public void setHeight(float height) {  
            this.height = height;  
        }  
    }  
      
      
    class Wolf implements Serializable{  
          
        /**  
         *   
         */  
        private static final long serialVersionUID = -1501152003733531169L;  
      
        private String type;  
          
        private String color;  
      
        public String getType() {  
            return type;  
        }  
      
        public void setType(String type) {  
            this.type = type;  
        }  
      
        public String getColor() {  
            return color;  
        }  
      
        public void setColor(String color) {  
            this.color = color;  
        }  
    }  

    
####2) test

    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
    import java.io.IOException;  
    import java.io.ObjectInputStream;  
    import java.io.ObjectOutputStream;  
      
    public class DogTest {  
          
        public static void serializable() throws IOException{  
            ChineseGardenDog dog = new ChineseGardenDog();  
            dog.setColor("white");  
            dog.setType("Chinese garden dog");  
            dog.setHeight(55);  
            FileOutputStream fos = new FileOutputStream("dog.txt");  
            ObjectOutputStream oos = new ObjectOutputStream(fos);  
            oos.writeObject(dog);  
            oos.flush();  
            oos.close();  
        }  
          
        public static void deSerializable() throws IOException,ClassNotFoundException{  
            FileInputStream sfis = new FileInputStream("dog.txt");  
            ObjectInputStream sois = new ObjectInputStream(sfis);  
            Wolf wolf = (Wolf) sois.readObject();  
            System.out.println(wolf.getType() +"<------->"+ wolf.getColor());  
        }  
          
          
        public static void main(String\[\] args) throws IOException ,ClassNotFoundException{  
            serializable();  
            deSerializable();  
        }  
    }  
```    

//Test results: Chinese garden dog < ------- > white.  
      
\### 5.1 translation of documents  
      
>Classes that need to designate a replacement when an instance of it is read from the stream should implement this special method with the exact signature.  
>  
>ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;  
>  
>This readResolve method follows the same invocation rules and accessibility rules as writeReplace.  
      
//When reading an instance from the data stream, the class that specifies the replacement needs to implement this special method.

ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

readResolve Labeling methods follow and writeReplace The same invocation and accessibility rules.  
      
\### 5.2 code verification

//Note: the write object instance and read object instance of this method are the same object (applicable to single instance mode).

\#### 1) Label method not implemented

//Entity class:

```       
        import java.io.Serializable;  
        public class Mouse implements Serializable{  
            /**  
             *   
             */  
            private static final long serialVersionUID = -8615238438948214201L;  
              
            private String name;  
              
            public static Mouse INSTANCE;  
              
              
            public static Mouse getInstance(){  
                if(INSTANCE == null){  
                    INSTANCE = new Mouse();  
                }  
                return INSTANCE;  
            }  
          
            public String getName() {  
                return name;  
            }  
          
            public void setName(String name) {  
                this.name = name;  
            }  
        }  

        
Test class:

        import java.io.FileInputStream;  
        import java.io.FileOutputStream;  
        import java.io.IOException;  
        import java.io.ObjectInputStream;  
        import java.io.ObjectOutputStream;  
          
        public class MouseTest {  
              
            public static void serializable() throws IOException{  
                Mouse mouse= Mouse.getInstance();  
                mouse.setName("Jerry");  
                FileOutputStream fos = new FileOutputStream("mouse.txt");  
                ObjectOutputStream oos = new ObjectOutputStream(fos);  
                System.out.println("Write object hash value = "+ mouse.hashCode());  
                oos.writeObject(mouse);  
                oos.flush();  
                oos.close();  
            }  
              
            public static void deSerializable() throws IOException,ClassNotFoundException{  
                FileInputStream sfis = new FileInputStream("mouse.txt");  
                ObjectInputStream sois = new ObjectInputStream(sfis);  
                Mouse mouse = (Mouse) sois.readObject();  
                System.out.println("read object hash value = " +mouse.hashCode());  
            }  
              
            public static void main(String\[\] args) throws IOException, ClassNotFoundException {  
                serializable();  
                deSerializable();  
            }  
        }  

        
Test results:

Write object hash value = 366712642

Read object hash value = 1096979270
    
####2) implementation of label method: (the test class does not change, and the entity class adds readResolve() method)
    
Entity class:

        import java.io.ObjectStreamException;  
        import java.io.Serializable;  
          
        public class Mouse implements Serializable{  
            /**  
             *   
             */  
            private static final long serialVersionUID = -8615238438948214201L;  
              
            private String name;  
              
            public static Mouse INSTANCE;  
              
              
            public static Mouse getInstance(){  
                if(INSTANCE == null){  
                    INSTANCE = new Mouse();  
                }  
                return INSTANCE;  
            }  
          
            public String getName() {  
                return name;  
            }  
          
            public void setName(String name) {  
                this.name = name;  
            }  
              
            private Object readResolve() throws ObjectStreamException{  
                return INSTANCE;  
            }  
        }  

       
Test results:

Write object hash value = 366712642

Read object hash value = 366712642
            
Speculation: the specified object instance written and read are the same.
            
###6.1 translation of documents
    

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an {@link InvalidClassException}.  A serializable class can declare its own serialVersionUID explicitly by declaring a field named <code>"serialVersionUID"</code> that must be static, final, and of type <code>long</code>: 

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification.  However, it is <em>strongly recommended</em> that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected <code>InvalidClassException</code>s during deserialization.  Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value.  It is also strongly advised that explicit serialVersionUID declarations use the <code>private</code> modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.
    
   
### 6.2 code verification for the implementation of Serializable interface

Parent class: Person class

    public class Person {  
          
        public String name;  
          
        public String gender;  
          
        public int age;  
          
        float height;  
          
      
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
      
        public String getGender() {  
            return gender;  
        }  
      
        public void setGender(String gender) {  
            this.gender = gender;  
        }  
      
        public int getAge() {  
            return age;  
        }  
      
        public void setAge(int age) {  
            this.age = age;  
        }  
      
        public float getHeight() {  
            return height;  
        }  
      
        public void setHeight(float height) {  
            this.height = height;  
        }  
    }  

Subclass: Male

    import java.io.Serializable;  
      
    public class Male extends Person implements Serializable{  
        /**  
         *   
         */  
        private static final long serialVersionUID = -7361904256653535728L;  
          
        public boolean beard;  
          
      
      
        public boolean havaBeard(int age){  
            boolean flag = false;  
              
            if(age>=18){  
                flag = true;  
            }  
            return flag;  
        }  
      
      
      
        public boolean isBeard() {  
            return beard;  
        }  
      
      
      
        public void setBeard(boolean beard) {  
            this.beard = beard;  
        }  
    }  

Third level subclass: Students class

    public class Students extends Male{  
          
        private static final long serialVersionUID = -6982821977091370834L;  
      
        public String stuCard;  
          
        private int grades;  
      
        public String getStuCard() {  
            return stuCard;  
        }  
      
        public void setStuCard(String stuCard) {  
            this.stuCard = stuCard;  
        }  
      
        public int getGrades() {  
            return grades;  
        }  
      
        public void setGrades(int grades) {  
            this.grades = grades;  
        }  
    }  

Class: Female class

    import java.io.Serializable;  
      
    public class Female implements Serializable{  
          
        private static final long serialVersionUID = 6907419491408608648L;  
      
        public String name;  
          
        public String gender;  
          
        public int age;  
          
        float height;  
      
          
          
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
      
        public String getGender() {  
            return gender;  
        }  
      
        public void setGender(String gender) {  
            this.gender = gender;  
        }  
      
        public int getAge() {  
            return age;  
        }  
      
        public void setAge(int age) {  
            this.age = age;  
        }  
      
        public float getHeight() {  
            return height;  
        }  
      
        public void setHeight(float height) {  
            this.height = height;  
        }  
    }  

Test class: SubTypeSerializable

    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
    import java.io.IOException;  
    import java.io.ObjectInputStream;  
    import java.io.ObjectOutputStream;  
      
    public class SubTypeSerializable {

    public static void main(String\[\] args) throws IOException, ClassNotFoundException{  
          
        /**(1) , Person entity class, serialization interface not implemented, no parent class*/  
        FileOutputStream fo = new FileOutputStream("person.txt");  
        ObjectOutputStream ss = new ObjectOutputStream(fo);  
        Person person = new Person();  
        person.setAge(100);  
        person.setGender("Gender");  
        person.setHeight(165);  
        person.setName("Human beings");  
        ss.writeObject(person);  
        ss.flush();  
        ss.close();  
          
        //De serialization  
        FileInputStream sfis = new FileInputStream("person.txt");  
        ObjectInputStream sois = new ObjectInputStream(sfis);  
        Person ps = (Person) sois.readObject();  
        System.out.println(ps.getName() +" "+ps.getGender()+" "+ps.getHeight() +" "+ps.getAge());  
      
        /**Result:  
            Exception occurred during writeObject(person) execution  
        Exception in thread "main" java.io.NotSerializableException:  
            com.springboot.SpringBootDemo.serializable.Person  
            at java.io.ObjectOutputStream.writeObject0(Unknown Source)  
            at java.io.ObjectOutputStream.writeObject(Unknown Source)  
            at com.springboot.SpringBootDemo.serializable.SubTypeSerializable.main(SubTypeSerializable.java:21)  
         Exception in thread "main" java.io.WriteAbortedException: writing aborted;    java.io.NotSerializableException: com.springboot.SpringBootDemo.serializable.Person  
            at java.io.ObjectInputStream.readObject0(Unknown Source)  
            at java.io.ObjectInputStream.readObject(Unknown Source)  
            at com.springboot.SpringBootDemo.serializable.SubTypeSerializable.main(SubTypeSerializable.java:28)  
         \* */  
        System.out.println("<--------------------------------------------------------------------------->");  
          
      
        /**(2) . Male inherits the parent class Person and implements the serialization interface. The parent class Person does not implement the serialization interface*/  
        FileOutputStream fos = new FileOutputStream("male.txt");  
        ObjectOutputStream oos = new ObjectOutputStream(fos);  
        Male male = new Male();  
        /**  
         \* Property of Person, the parent of its parent  
         *   
         \* public String name;  
           public String gender;  
           public int age;  
           float height;  
         \* */  
        male.setName("Zhang San");  
        male.setGender("Male");  
        male.setAge(25);  
        male.setHeight(175);  
        /**  
         \* Its own properties  
         \* public boolean beard;  
         \* */  
        male.setBeard(true);  
        oos.writeObject(male);  
        oos.flush();  
        oos.close();  
          
        //De serialization  
        FileInputStream fis = new FileInputStream("male.txt");  
        ObjectInputStream ois = new ObjectInputStream(fis);  
        Male ml = (Male) ois.readObject();  
        System.out.println(ml.getName() +" "+ml.getGender()+" "+ml.getHeight() +" "+ml.getAge()+" "+male.isBeard());  
          
        /**Result:  
         \* Parent class is not serialized, only the only child class property is serialized  
         *   
         \* ml.getName() == null   
         \* ml.getGender() == null   
         \* ml.getHeight() == 0.0   
         \* ml.getAge() == 0   
         \* male.isBeard() == true  
         \* Parent property:  
         \*  public String name;  
            public String gender;  
            public int age;  
            float height;  
                       No serialization is implemented;  
                    Self attributes:  
            public boolean beard;  
                        Implement serialization  
         \* */  
          
        System.out.println("<--------------------------------------------------------------------------->");  
     
        /**(3) , male implements the serialization interface, no parent class*/  
        FileOutputStream ffos = new FileOutputStream("female.txt");  
        ObjectOutputStream foos = new ObjectOutputStream(ffos);  
        Female female = new Female();  
        /**  
         \* Its own properties  
         \* public String name;  
           public String gender;  
           public int age;  
           float height;  
         **/  
        female.setAge(25);  
        female.setGender("Female sex");  
        female.setHeight(165);  
        female.setName("Zhang Fang");  
        foos.writeObject(female);  
        foos.flush();  
        foos.close();  
          
        //De serialization  
        FileInputStream ffis = new FileInputStream("female.txt");  
        ObjectInputStream fois = new ObjectInputStream(ffis);  
        Female fm = (Female) fois.readObject();  
        System.out.println(fm.getName() +" "+fm.getGender()+" "+fm.getHeight() +" "+fm.getAge());  
          
        /**Result:  
         \* Serialization of self properties  
         *   
         \* fm.getName() == Zhang Fang  
         \* fm.getGender() == Female  
         \* fm.getHeight() == 165.0   
         \* fm.getAge() == 25  
         \* All properties are serialized*/  
        System.out.println("<--------------------------------------------------------------------------->");  
          
          
        /**(4) . Students does not implement the serialization interface. It inherits the parent class Male. Its parent class inherits the parent class Person. It implements the serialization interface itself. Its parent class Person does not implement the serialization interface*/  
        FileOutputStream stufos = new FileOutputStream("students.txt");  
        ObjectOutputStream stuoos = new ObjectOutputStream(stufos);  
        Students students = new Students();  
        /**  
         \* Property of Person, the parent of its parent  
         *   
         \* public String name;  
           public String gender;  
           public int age;  
           float height;  
         \* */  
        students.setName("Xiao Ming Wang");  
        students.setGender("Male");  
        students.setAge(15);  
        students.setHeight(160);  
        /**  
         \* Its parent class Male attribute  
         \* public boolean beard;  
         \* */  
        students.setBeard(true);  
        /**  
         \* Self attribute  
         \* public String stuCard;  
           private int grades;  
         \* */  
        students.setStuCard("1234567890987");  
        students.setGrades(300);  
        stuoos.writeObject(students);  
        stuoos.flush();  
        stuoos.close();  
          
        //De serialization  
        FileInputStream stufis = new FileInputStream("students.txt");  
        ObjectInputStream stuois = new ObjectInputStream(stufis);  
        Students st = (Students) stuois.readObject();  
        System.out.println(st.getName() +" "+st.getGender()+" "+st.getAge()+" "+st.getHeight()+" "+st.isBeard()+" "+st.getStuCard()+" "+st.getGrades());  
          
        /**Result:  
         \* The parent property of the parent class does not realize serialization. The parent class implements serialization and implements serialization itself  
         \* st.getName() == null   
         \* st.getGender() == null   
         \* st.getAge() == 0   
         \* st.getHeight() == 0.0   
         \* st.isBeard() == true   
         \* st.getStuCard() == 1234567890987   
         \* st.getGrades() == 300  
         \* public String stuCard;  
              private int grades;  
                Implement serialization;  
               And the parent class Male attribute  
              public boolean beard  
                Implement serialization;  
               Person, the parent of the parent  
            public String name;  
            public String gender;  
            public int age;  
            float height;  
                       Serialization not implemented  
         \* */  
        }  
    }  

###6.3 review
 
1) When using ObjectInputStream and ObjectOutputStream to write out objects, the classes of the objects they write to need to implement the java.io.Serializable serialization interface. Otherwise, the writeObject() exception will be reported:

            Exception in thread "main" java.io.NotSerializableException: com.springboot.SpringBootDemo.serializable.Person  
            at java.io.ObjectOutputStream.writeObject0(Unknown Source)  
            at java.io.ObjectOutputStream.writeObject(Unknown Source)  
            at com.springboot.SpringBootDemo.serializable.SubTypeSerializable.main(SubTypeSerializable.java:21)  
            readObject()Exception:   
            Exception in thread "main" java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.springboot.SpringBootDemo.serializable.Person  
                  java.io.ObjectInputStream.readObject0(Unknown Source)  
                 at java.io.ObjectInputStream.readObject(Unknown Source)  
                 at com.springboot.SpringBootDemo.serializable.SubTypeSerializable.main(SubTypeSerializable.java:28)  

2) The parent class does not implement the java.io.Serializable serialization interface, and its subclasses can still be serialized, but when its subclasses are reading and writing object serialization, the parent class cannot be serialized, so it can only realize serialization itself;

3) The java.io.Serializable serializable interface is implemented by itself, and it will be serialized when reading and writing objects;

4) The parent class implements the java.io.Serializable serialization interface. Its subclass does not need to declare the implementation of serialization again. When the subclass is reading and writing object serialization, both the parent class and the subclass are implemented serialization.
     
###7.1 summary
  
####1) java.io.Serializable interface

First, the Serializable class is an interface, so object serialization is not implemented by Serializable;

Secondly, Serializable is a tag. When reading this tag, various Serializable classes will serialize in their own way.

####2) what is serialization for and why it is needed

We know that when two processes communicate remotely, they can send various types of data to each other, including text, pictures, audio, video, etc., which will be transmitted on the network in the form of binary sequence.

So when two Java processes communicate, can object transfer between processes be realized? The answer is yes! How to do it? This requires Java serialization and deserialization!

In other words: on the one hand, the sender needs to convert the Java object into a byte sequence, and then transmit it on the network; on the other hand, the receiver needs to recover the Java object from the byte sequence.

When we understand why we need Java serialization and deserialization, we naturally think about the benefits of Java serialization.

-It can record the data structure or the state of the Object (that is, the value of the entity variable Object [Note: not Class] at a certain time point) through serialization, and save the data temporarily or permanently to the hard disk (usually stored in a file);
-Using serialization to realize remote communication, and in the process of data transmission or use, it can ensure the integrity and transitivity of data structure or object state, that is, transferring the byte sequence of the object on the network.

Author: Zhong Sheng

First: "wild pointer"

Source: Yixin Institute of Technology

Posted by oldefezziwig on Tue, 10 Mar 2020 22:53:22 -0700