This is the seventh day of my participation in the August More text Challenge. For details, see:August is more challenging
Serialization and deserialization techniques are used when we want to store a Java object on a temporary medium or over a network, etc. Java serialization is the process of converting an object to a sequence of bytes, while deserialization is the process of converting only a sequence of bytes to the target object.
Serialization is implemented in Java through two interfaces: Serializable and Externalizable.
public interface Serializable {}Copy the code
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
Copy the code
Let’s take a look at how they are used:
Serializable implements Serializable
@Data
public class Parent implements Serializable {
public static final long serialVersionUID = 1L;
private String name;
private Integer age;
private transient Integer weight;
public static void main(String[] args) throws IOException, ClassNotFoundException {
Parent parent = new Parent();
parent.setName("Tom");
parent.setAge(30);
parent.setWeight(120);
/ / the serialization
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./data.txt"));
oos.writeObject(parent);
oos.close();
// Deserialize
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./data.txt")); Parent parent1 = (Parent) ois.readObject(); System.out.println(parent1.getName()); System.out.println(parent1.getAge()); System.out.println(parent1.Weight()); }}/*
Tom
30
null
*/
Copy the code
As you can see, Serializable is just a marker, we can serialize objects to the media we want to send through ObjectOutputStream and ObjectInputStream. Of course, using their writeObject and readObject methods is just the default serialization methods. If we want to customize our own serialization methods, we can override these two methods in our own class.
private void writeObject(ObjectOutputStream out) throws IOException {
// Add CE to the name suffix
out.writeObject(new StringBuffer(this.name).append("CE"));
out.writeInt(age);
out.writeInt(weight);
}
private void readObject(ObjectInputStream ins) throws IOException,ClassNotFoundException{
this.name = ((StringBuffer)ins.readObject()).toString();
this.age = ins.readInt();
this.weight = ins.readInt();
}
/*
TomCE
30
120
*/
Copy the code
If we implement these methods, ObjectOutputStream and ObjectInputStream will call these methods instead of their default implementations! (Also note that if we specify write and read the weight variable, then the transient keyword is not valid.)
Externalizable implementation
@Data
public class Child implements Externalizable {
private String name;
private Integer age;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeInt(age);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.name = (String) in.readObject();
this.age = in.readInt();
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Child child = new Child();
child.setName("Justin");
child.setAge(10);
/ / the serialization
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./data2.txt"));
oos.writeObject(parent);
oos.close();
// Deserialize
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./data2.txt")); Child child1 = (Child) ois.readObject(); System.out.println(child1.getName()); System.out.println(child1.getAge()); }}/*
Justin
10
*/
Copy the code
Externalizable is inherited from the Serializable interface, but it requires us to override the writeExternal() and readExternal() methods ourselves. And classes that implement the Externalizable interface must provide a public constructor that takes no arguments.
It just provides an interface to the custom way we mentioned above.
Some serialization-related issues
There’s a lot to know about serialization, but here’s a reminder.
SerialVersionUID role
JAVA serialization verifies that the version is consistent by determining the serialVersionUID of the class. When deserialization is performed, the JVM compares the serialVersionUID in the incoming byte stream to the local serialVersionUID of the corresponding entity class. If the same instructions are consistent, you can deserialize them, otherwise you will get an exception that is consistent with the deserialized version, called InvalidCastException.
We need to have a class file when we need to deserialize a sequence of bytes, but the class file will change iteratively as the project progresses. At some point we may no longer support objects created and serialized by the previous class. In this case, we can change the serialVersionUID version number so that the original object will not be serialized successfully.
And we should specify the version number, because if we don’t, the JVM will automatically generate an ID based on the class information, so that even if our class is compatible with the data, or if the class is unchanged but the JVM implementation is different, the data will not be serialized correctly. It is recommended that we add this variable to all classes that need to be serialized.
Why implement Serializable if you want serialization?
Serializable is used to mark classes that can be serialized so that some classes cannot be serialized! We could make Serializable for all Java classes by default, but Serializable is risky. For example, Effective Java describes a number of disadvantages of implementing Serializable:
- Once a class is published, the flexibility to “change the implementation of the class” is greatly reduced. If a class implements the Serializable interface, it becomes part of the class’s export API.
- Increases the possibility of bugs and security holes. Serialization is a mechanism for object creation outside the language, and deserialization is a “hidden constructor” that has the same characteristics as other constructors. Therefore, the deserialization process must ensure all the constraints.
- As new releases are released, the associated testing burden increases.
- When you serialize an object, you serialize not only the current object itself, but also other objects referenced by the object. If an object contains member variables such as container classes and is deeply referenced (the object is in the form of a linked list), the serialization overhead is high and must be handled by some other means.
So Java really want is to get all the classes can implement serialization, (because the Socket, for example, Thread if these classes can be serialized for transmission or save, even if they are deserialized, we cannot allocate resources) only when we definitely need this class needs to be serialized, we did not add annotations, Then the JVM will allow it (ObjectXputStream’s readObject and writeObject methods will check if the class is instanceof Serializable).
Can static variables be serialized?
No, it doesn’t belong to the object, it belongs to the class.
If you serialize the same object multiple times, will you serialize the same object multiple times?
No, when an object is serialized, you write it multiple times, it’s still just an object. When deserialized, the deserialized object is the same object. Such as
oos.writeObject(o1);
oos.writeObject(o2);
(o1 = ooi.readObject()) == (o2 = ooi.readObject())
Copy the code
When an object is serialized, each object is given a number. When it is serialized again, it checks to see if the object has been serialized. If so, it prints the number instead of sequence the object.
Transient keyword
Specifying that a property is not serialized is not guaranteed to be effective, such as the custom serialization method above, which can be serialized and deserialized even if specified.
Some serialization considerations
- If a property of a class is an object class, then the object class must also implement the Serializable interface or the serialization fails.
- If a subclass implements the Serializable interface and a parent class does not implement the Serializable interface, the parent class will not be serialized, that is, the properties of the parent class will be lost.
- The parent class implements the Serializable interface; the subclass does not need to.