1. Serializable接口
只是一个标记接口,不包含任何的方法的定义
public class Teacher implements Serializable {
private static final long serialVersionUID = 1915987587027965086L;
private String name;
private Integer age;
public Teacher(String name, Integer age) {
this.name = name;
this.age = age;
}
//getter,setter......
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
作用:
serialVersionUID用于验证反序列化的类和本地的类的版本是否一致,比如从网络获取反序列化的UID为1L,而本地的UID为2L,则会产生InvalidCastException异常,只有版本一致才能转化
同时本地Classpath也必须有这个类的.class文件,否者也没有比较UID这么一说,若不存在该文件会产生ClassNotFoundException
生成规则:
一是默认的1L,比如:private static final long serialVersionUID = 1L;
二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段
2. Externalizable接口
继承自Serializable,定义了两个方法,用于序列化的反序列化时自动调用,可以自定义需要序列化的属性,以及属性的初始化
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
序列化时自动调用writeExternal,在方法中可以自定义那些属性字段需序列化
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeObject(age);
//out.writeObject(teacher); 无需序列化则省略
}
反序列化自动调用readExternal,在反序列化时可以设置被忽略字段的初始值
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = (String)in.readObject();
age = (Integer)in.readObject();
//teacher = (Teacher)in.readObject();
teacher = new Teacher("default", 0); //自定义初始值
}
序列化和反序列化的字段的顺序需要一致,否则不同类型的数据会产生ClassCastException
会调用Student的默认的无参构造函数,必须提供无参构造函数(没有无参构造函数:InvalidClassException: com.sxd.bean.Student; no valid constructor),对于Serializable对象是完全以它存储的二进制位为基础来构造,而不是通过构造器构造的,对于Enternalizable对象会通过默认无参构造函数初始化构造对象
3. ObjectOutputStream/ObjectInputStream
Student类中的属性必须都为可序列化对象,有一个为不可序列化对象(没有继承Serializable)则会产生java.io.NotSerializableException异常
public class SerializeableTest {
public static void main(String[] args) throws Exception {
writeSerializeStudent();
readSerializeStudent();
}
private static void writeSerializeStudent() throws Exception {
Teacher teacher = new Teacher("haha", 36);
Student student = new Student("sxd", 22, teacher);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("F:/student.out"));
oos.writeObject(student);
oos.close();
}
public static void readSerializeStudent() throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("F:/student.out"));
Student student = (Student)ois.readObject();
System.out.println(student);
}
}
//Student
public class Student implements Externalizable {
private static final long serialVersionUID = 2662734246959142949L;
private String name;
private Integer age;
private Teacher teacher;
public Student() {
System.out.println("constructor");
}
public Student(String name, Integer age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
//getter,setter......
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeObject(age);
out.writeObject(teacher);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = (String)in.readObject();
age = (Integer)in.readObject();
//teacher = new Teacher("default", 0);
teacher = (Teacher)in.readObject();
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
4. transient关键字
处理继承Externalizable实现相关的方法,在writeExternal方法内部决定属性的序列化与否之外,还可以通过transient实现,被该关键字修饰的字段会自动关闭序列化操作,和Serializable一起使用的效果和Externalizabel类似