对象的序列化/反序列化
对象序列化,就是将Object转换成byte序列,反之叫做对象的反序列化。
序列化流(ObjectOutputStream),是一个过滤流 --> writeObject,
反序列化流(ObjectInputStream) --> readObject.
序列化接口(Serializable)
对象必须实现序列化接口才能进行序列化,否则将出现NoSerializableException
异常。此接口没有任何方法,只是一个标准。
创建一个Person.java实体类:
public class Person implements Serializable {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
写一个对象流测试类:
public class ObjectTest {
public static void main(String[] args) throws IOException {
String file = "F:\\Code\\JavaSE\\obj.txt";
// 对象序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
Person student = new Person("张三", 22);
oos.writeObject(student);
oos.flush();
oos.close();
try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
Person per = (Person) ois.readObject();
System.out.println(per);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
输出结果:
Person{name='张三', age=22}
在进行对象序列化操作时,并不希望所有的变量都进行序列化操作,这时可以在变量前加上transient
关键字,使得该变量不进行序列化操作,并不是说不做JVM默认的序列化就不能序列化了,也可以自己完成这个变量的序列化。
Person.java中给age变量前面加上transient
关键字,添加以下两种方法:
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject(); //把JVM能默认序列化的元素进行序列化操作
s.writeObject(age); //被transient修饰的变量,自己完成序列化操作
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject(); //把JVM能默认反序列化的元素进行反序列化操作
this.age = (Integer) s.readObject();//自己完成age的反序列化操作
}
加上这两个方法后,即使变量前有transient
关键字修饰,也可以进行序列化/反序列化操作。
分析ArrayList源码中序列化和反序列化的问题
序列化中,子类和父类之间的调用:一个类实现了序列化接口,继承它的子类都能够进行序列化操作。
序列化显式创建对象,需要递归调用父类方法。
对子类对象进行反序列化操作时,如果其父类没有实现序列化接口,那么其父类的构造函数会被调用。