Serialization and deserialization of objects
1) Object serialization is to convert the Object object into byte sequence, otherwise it is called deserialization of the object.
2) Serialization stream (ObjectOutputStream) is a filtered stream of bytes - writeObject() method
Deserialization stream (ObjectInputStream) - readObject() method
3) Serializable interface (Serializable)
The object must implement the serialization interface before it can be serialized, otherwise an exception will occur.
Note: This interface does not have any methods, it is just a [standard]
1. The most basic sequence The process of serialization and deserialization
Serialization and deserialization are all operated on Object objects. Here is a simple case to demonstrate the object serialization and deserialization. process.
1. Create a new Student class (test class)
Note: A class that implements the serialization interface is required to perform serialization operations! !
@SuppressWarnings("serial") public class Student implements Serializable{ private String stuno;//id private String stuna;//姓名 private int stuage;//年龄 public String getStuno() { return stuno; } public void setStuno(String stuno) { this.stuno = stuno; } public String getStuna() { return stuna; } public void setStuna(String stuna) { this.stuna = stuna; } public Student() { super(); // TODO Auto-generated constructor stub } public Student(String stuno, String stuna, int stuage) { super(); this.stuno = stuno; this.stuna = stuna; this.stuage = stuage; } @Override public String toString() { return "Student [stuno=" + stuno + ", stuna=" + stuna + ", stuage=" + stuage + "]"; } public int getStuage() { return stuage; } public void setStuage(int stuage) { this.stuage = stuage; } }
2. Serialize instances of the Student class into files
The basic operation steps are as follows:
1), specify serialization and save file
2), construct the ObjectOutputStream class
3), construct a Student class
4), use the writeObject method to serialize
5), Use the close() method to close the stream
String file="demo/obj.dat"; //对象的序列化 ObjectOutputStream oos=new ObjectOutputStream( new FileOutputStream(file)); //把Student对象保存起来,就是对象的序列化 Student stu=new Student("01","mike",18); //使用writeObject方法序列化 oos.writeObject(stu); oos.close();
Running results: You can see that the serialized file obj.dat was generated in the demo directory
3. Deserialize the file and read out the Student class object
The basic operation steps are as follows:
1), specify the file to be deserialized
2), Construct the ObjectInputStream class
3), use the readObject method to deserialize
1), and use the close method to close the stream
String file="demo/obj.dat"; ObjectInputStream ois =new ObjectInputStream( new FileInputStream(file)); //使用readObject()方法序列化 Student stu=(Student)ois.readObject();//强制类型转换 System.out.println(stu); ois.close();
Running results:
Note: When deserializing a file, the objects taken out by the readObject method are of type Object by default and must be forced to the corresponding type.
2. Transient and ArrayList source code analysis
In the daily programming process, we sometimes do not want all the elements of a class to be Serialized by the compiler, what should I do at this time?
Java provides a transient keyword to modify elements that we do not want to be automatically serialized by the jvm. Let’s briefly explain this keyword.
transient keyword: The element modified by transient will not be serialized by jvm by default, but you can complete the serialization of this element by yourself.
Note:
1) In future network programming, if there are certain elements that do not need to be transmitted, they can be modified with transient to save traffic; yes Efficient element serialization to improve performance.
2) You can use writeObject to complete the serialization of this element yourself.
ArrayList is optimized using this method. ArrayList's core container Object[] elementData uses transient modification, but writeObject implements serialization of the elementData array itself. Only valid elements in the array are serialized. readObject is similar.
--------------My own way of serialization- --------------
Add two methods to the class to be serialized (These two methods are derived from the ArrayList source code Two special methods extracted from JVM will automatically use these two methods to help us complete this action.
There is another question here. Why do we still need to complete serialization and deserialization manually? What is the meaning?
This problem needs to be analyzed from the source code of ArrayList:
It can be seen that the source code of ArrayList The purpose of self-serialization: The bottom layer of ArrayList is an array. Self-serialization can filter invalid elements in the array and only serialize valid elements in the array, thereby improving performance
.Therefore, during the actual programming process, we can complete the serialization ourselves as needed to improve performance.
三、序列化中子父类构造函数问题
在类的序列化和反序列化中,如果存在子类和父类的关系时,序列化和反序列化的过程又是怎么样的呢?
这里我写一个测试类来测试子类和父类实现序列化和反序列化时构造函数的实现变化。
public static void main(String[] args) throws IOException { // TODO Auto-generated method stub String file="demo/foo.dat"; ObjectOutputStream oos=new ObjectOutputStream( new FileOutputStream(file)); Foo2 foo2 =new Foo2(); oos.writeObject(foo2); oos.flush(); oos.close(); } } class Foo implements Serializable{ public Foo(){ System.out.println("foo"); } } class Foo1 extends Foo{ public Foo1(){ System.out.println("foo1"); } } class Foo2 extends Foo1{ public Foo2(){ System.out.println("foo2"); } }
运行结果:这是序列化时递归调用了父类的构造函数
接来下看看反序列化时,是否递归调用父类的构造函数。
ObjectInputStream ois=new ObjectInputStream( new FileInputStream(file)); Foo2 foo2=(Foo2)ois.readObject(); ois.close();
运行结果:控制台没有任何输出。
那么这个结果是否证明反序列化过程中父类的构造函数就是始终不调用的呢?
然而不能证明!!
因为再看下面这个不同的测试例子:
class Bar { public Bar(){ System.out.println("bar"); } } class Bar1 extends Bar implements Serializable{ public Bar1(){ System.out.println("bar1"); } } class Bar2 extends Bar1{ public Bar2(){ System.out.println("bar2"); } }
我们用这个例子来测试序列化和反序列化。
序列化结果:
反序列化结果:没实现序列化接口的父类被显示调用构造函数
【反序列化时】,向上递归调用构造函数会从【可序列化的一级父类结束】。即谁实现了可序列化(包括继承实现的),谁的构造函数就不会调用。
总结:
1)父类实现了serializable接口,子类继承就可序列化。
子类在反序列化时,父类实现了序列化接口,则不会递归调用其构造函数。
2)父类未实现serializable接口,子类自行实现可序列化
子类在反序列化时,父类没有实现序列化接口,则会递归调用其构造函数。
本文来自 java入门 栏目,欢迎学习!
The above is the detailed content of Java object serialization and deserialization. For more information, please follow other related articles on the PHP Chinese website!