Serialization and Deserialization of Objects in Java Development

Keywords: Java jvm network xml

Serializable and Deserialize

Serialization is the process of converting the state information of an object into a form that can be stored or transmitted. Generally, an object is stored in a storage medium, such as a file or a billionaire buffer. In the process of network transmission, it can be byte or XML format. The byte or XML encoding format can restore exactly the same object. This opposite process is also known as deserialization.

Serialization and deserialization of Java objects

In Java, we can create objects in many ways, and we can reuse them as long as they are not recycled. However, the Java objects we created are all in the heap memory of the JVM. Only when the JVM is running can these objects exist. Once the JVM stops running, the state of these objects is lost.

But in real application scenarios, we need to persist these objects and be able to re-read them when needed. Java object serialization can help us achieve this function.

Object serialization is an object persistence method built in Java language. By object serialization, the state of the object can be saved as a byte array, and the byte array can be converted into an object by deserialization when necessary. Object serialization can be easily converted between active objects and byte arrays (streams) in the JVM.

In Java, object serialization and deserialization are widely used in RMI (remote method call) and network transmission.

Relevant interfaces and classes

Java provides a set of convenient API s for developers to serialize and deserialize Java objects. These include the following interfaces and classes:

java.io.Serializable

java.io.Externalizable

ObjectOutput

ObjectInput

ObjectOutputStream

ObjectInputStream

Serializable interface

Class enables serialization by implementing the java.io.Serializable interface. Classes that do not implement this interface will not be able to serialize or deserialize any of their states. All subtypes of serializable classes themselves are serializable. Serialized interfaces have no methods or fields and are used only to identify serializable semantics. (The interface does not have methods and fields. Why can only objects of classes that implement the interface be serialized? )

When trying to serialize an object, encounter an object that does not support the Serializable interface. In this case, NotSerializableException will be thrown.

If the serialized class has a parent class, and if you want to persist the variables defined in the parent class at the same time, the parent class should also integrate the java.io.Serializable interface.

Here is a class that implements the java.io.Serializable interface

package com.hollischaung.serialization.SerializableDemos;
import java.io.Serializable;
/**
 * Created by hollis on 16/2/17.
 * Implementing Serializable Interface
 */
public class User1 implements Serializable {
 
    private String name;
    private int age;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Serialize and deserialize with the following code

package com.hollischaung.serialization.SerializableDemos;
 
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
 
import java.io.*;
/**
 * Created by hollis on 16/2/17.
 * SerializableDemo1 Combining Serializable Demo2 to illustrate that a class must implement the Serializable interface in order to be serialized
 */
public class SerializableDemo1 {
 
    public static void main(String[] args) {
        //Initializes The Object
        User1 user = new User1();
        user.setName("hollis");
        user.setAge(23);
        System.out.println(user);
 
        //Write Obj to File
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
            oos.writeObject(user);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(oos);
        }
 
        //Read Obj from File
        File file = new File("tempFile");
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream(file));
            User1 newUser = (User1) ois.readObject();
            System.out.println(newUser);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(ois);
            try {
                FileUtils.forceDelete(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
 
    }
}
 
//OutPut:
//User{name='hollis', age=23}
//User{name='hollis', age=23}

For more information on the use of Serializable, see the code example

Externalizable interface

In addition to Serializable, another serialization interface Externalizable is provided in java

To understand the difference between the Externalizable interface and the Serilizable interface, let's first look at the code and change the above code to use Externalizable.

package com.hollischaung.serialization.ExternalizableDemos;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
 
/**
 * Created by hollis on 16/2/17.
 * Implementing Externalizable Interface
 */
public class User1 implements Externalizable {
 
    private String name;
    private int age;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public void writeExternal(ObjectOutput out) throws IOException {
 
    }
 
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
 
    }
 
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package com.hollischaung.serialization.ExternalizableDemos;
 
import java.io.*;
 
/**
 * Created by hollis on 16/2/17.
 */
public class ExternalizableDemo1 {

 
// In order to facilitate understanding and save space, the operation of closing stream and deleting file is ignored. Don't forget when coding
// IOException throws directly
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //Write Obj to file
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
        User1 user = new User1();
        user.setName("hollis");
        user.setAge(23);
        oos.writeObject(user);
        //Read Obj from file
        File file = new File("tempFile");
        ObjectInputStream ois =  new ObjectInputStream(new FileInputStream(file));
        User1 newInstance = (User1) ois.readObject();
        //output
        System.out.println(newInstance);

    }
}
//OutPut:
//User{name='null', age=0}

Through the example above, we can find that the values of all attributes of the object obtained after serialization and deserialization of the User1 class become default values. That is to say, the state of the previous object has not been persisted. This is the difference between the Externalizable interface and the Serilizable interface:

Externalizable inherits Serializable, which defines two abstract methods: writeExternal() and readExternal(). When serializing and deserializing using the Externalizable interface, developers need to rewrite the writeExternal() and readExternal() methods. Since the serialization implementation details are not defined in the above two methods, the output is empty. It is also worth noting that when using Externalizable for serialization, when reading an object, the parametric constructor of the serialized class is called to create a new object, and then the field values of the saved object are filled into the new object separately. Therefore, the class that implements the Externalizable interface must provide a public parametric constructor.

As required, the code is as follows:

package com.hollischaung.serialization.ExternalizableDemos;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
 
/**
 * Created by hollis on 16/2/17.

* Implementation of Externalizable Interface and writeExternal and readExternal Methods
 

*/
public class User2 implements Externalizable {
 
    private String name;
    private int age;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.writeInt(age);
    }
 
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        age = in.readInt();
    }
 
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
 
package com.hollischaung.serialization.ExternalizableDemos;
 
import java.io.*;
 
/**
 * Created by hollis on 16/2/17.
 */
public class ExternalizableDemo2 {

 
// In order to facilitate understanding and save space, the operation of closing stream and deleting file is ignored. Don't forget when coding
// IOException throws directly
 

  public static void main(String[] args) throws IOException, ClassNotFoundException {
        //Write Obj to file
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
        User2 user = new User2();
        user.setName("hollis");
        user.setAge(23);
        oos.writeObject(user);
        //Read Obj from file
        File file = new File("tempFile");
        ObjectInputStream ois =  new ObjectInputStream(new FileInputStream(file));
        User2 newInstance = (User2) ois.readObject();
        //output
        System.out.println(newInstance);
    }
}
//OutPut:
//User{name='hollis', age=23}

This time, you can persist the previous object state.

If there is no parametric constructor in the User class, an exception is thrown at run time: java.io.InvalidClassException

For more examples of Externalizable interface usage, see Code Instances

ObjectOutput and ObjectInput interfaces

The ObjectInput interface extends from the DataInput interface to include object read operations.

The DataInput interface is used to read bytes from binary streams and reconstruct them based on all Java basic types of data. It also provides tools to reconstruct String from data in UTF-8 modified format.

For all data reading routines in this interface, an EOFException (one of IOExceptions) is thrown if the end of the file has been reached before the required number of bytes is read. If bytes cannot be read for reasons other than reaching the end of the file, IOException will be thrown instead of EOFException. In particular, IOException is thrown when the input stream is closed.

ObjectOutput extends the DataOutput interface to include write operations for objects.

The DataOutput interface is used to convert data from any Java base type to a series of bytes, which are written to a binary stream. It also provides a tool for converting String into UTF-8 modified format and writing the resulting series of bytes.

For all methods that write bytes in this interface, IOException is thrown if for some reason a byte cannot be written.

ObjectOutputStream class and ObjectInputStream class

As you can see from the previous code snippet, we usually use ObjectOutputStream's writeObject method to persist an object. The readObject of ObjectInputStream is used to read the object from the persistent storage.

More knowledge about ObjectInputStream and ObjectOutputStream is welcome to read my other two blogs: an in-depth analysis of Java serialization and deserialization, singletons and serialization

Transient keyword

The function of the Transient keyword is to control the serialization of variables. By adding the keyword before the variable declaration, the variable can be prevented from being serialized into the file. After being deserialized, the value of the Transient variable is set to the initial value, such as 0 in int type and null in object type. Extended knowledge about Transient keywords welcome to read in-depth analysis of Java serialization and deserialization

Serialization of ID

Whether the virtual machine allows deserialization depends not only on the consistency of the classpath and the functional code, but also on the consistency of the serialization IDs of the two classes (that is, private static final long series Version UID).

Serialization ID provides two generation strategies under Eclipse, one is fixed 1L, the other is random generation of long-type data without duplication (actually generated using JDK tools). Here is a suggestion that if there is no special requirement, it is possible to use default 1L to ensure the success of deserialization when the code is consistent. So what's the use of randomly generated serialized IDs? Sometimes, changing the serialized IDs can be used to restrict the use of certain users.

Reference material

Wikipedia

Understanding Java object serialization

Advanced understanding of Java serialization
Pay attention to the Wechat Public Number of "Power Node Java College" for more information. Now sign up. Java training You can take the Java beginner course for free and experience the learning atmosphere here first-hand.

Posted by bigdaddysheikh on Mon, 08 Apr 2019 19:51:31 -0700