Java序列化是指把Java对象转换为字节序列的过程,Java反序列化是指把字节序列恢复为Java对象的过 程。通过徐序列化和反序列化实现网络传输、本地存储的目的。
Serializable实现Java序列化
要实现Java对象的序列化,只要将类实现标识接口——Serializable接口即可,不需要我们重写任何方法就可以实现序列化。
示例:
实体类
// 学生类
public class Student implements Serializable {
private String stuNum;
private String name;
private List<String> teacherList;
// 构造及get/set方法省略
}
文件写入与读出工具类
public class MySerializeUtil {
/**
* 将对象序列化到指定文件中
*/
public static void mySerialize(Object obj, String fileName) throws IOException {
OutputStream out = new FileOutputStream(fileName);
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
objOut.close();
}
/**
* 从指定文件中反序列化对象
*/
public static Object myDeserialize(String fileName) throws IOException, ClassNotFoundException {
InputStream in = new FileInputStream(fileName);
ObjectInputStream objIn = new ObjectInputStream(in);
Object obj = objIn.readObject();
return obj;
}
}
测试:
public static void main(String[] args) {
List<String> teacherList=new ArrayList<>();
teacherList.add("王德");
teacherList.add("张震");
Student stu1=new Student("1001", "贾三桂", teacherList);
System.out.println("原始对象:"+stu1);
String fileName="stu01.txt";
try {
// 对象序列化
MySerializeUtil.mySerialize(stu1, fileName);
System.out.println("序列化原始对象完成!OK!");
// 对象的反序列化
Object obj=MySerializeUtil.myDeserialize(fileName);
if(obj instanceof Student){
Student stuNew= (Student) obj;
System.out.println("反序列化之后的对象:"+stuNew);
}
} catch (Exception e) {
e.printStackTrace();
}
}
结果:
部分属性的序列化
实现部分字段序列化的方式:
- 使用transient修饰符
- 使用static修饰符
- 默认方法writeObject和readObject
使用transient修饰符
修改实体类,将实体类中不想序列化的属性添加transient修饰词。
重新运行测试类的结果: 我们将实体类中的stuName和teacherList属性添加了transient修饰词,因此对象被序列化的时候忽略 这两个属性。通过运行结果可以看出:
使用static修饰符
static修饰符修饰的属性也不会参与序列化和反序列化。 修改实体类,将实体类中不想序列化的属性添加static修饰词。
结果:
默认方法writeObject和readObject
修改实体类,将transient修饰词去掉,添加两个方法。
我们在添加的方法中只对stuNum和stuName属性做了序列化和反序列化的操作,因此只有这个两个属性可以被序列化和反序列化。
分析:
Java调用ObjectOutputStream类检查其是否有私有的、无返回值的writeObject方法,如果有, 其会委托该方法进行对象序列化。
ObjectStreamClass类:在序列化(反序列化)的时候,ObjectOutputStream(ObjectInputStream) 会寻找目标类中的私有的writeObject(readObject)方法,赋值给变量 writeObjectMethod(readObjectMethod)。
如果writeObjectMethod != null(目标类中定义了私有的writeObject 方法),那么将调用目标类中的writeObject方法,如果如果writeObjectMethod == null,那么将调用 默认的defaultWriteFields方法来读取目标类中的属性。
readObject的调用逻辑和writeObject一样。
总结一下,如果目标类中没有定义私有的writeObject或readObject方法,那么序列化和反序列化的时候将调用默认的方法来根据目标类中的属性来进行序列化和反序列化,而如果目标类中定义了私有的 writeObject或readObject方法,那么序列化和反序列化的时候将调用目标类指定的writeObject或 readObject方法来实现。
Externalizable实现Java序列化
Externalizable继承自Serializable,使用Externalizable接口需要实现readExternal方法和 writeExternal方法来实现序列化和反序列化。
Externalizable接口继承了Serializable接口,所以实现Externalizable接口也能实现序列化和反序列 化。 Externalizable接口中定义了writeExternal和readExternal两个抽象方法,这两个方法其实对应 Serializable接口的writeObject和readObject方法。可以这样理解:Externalizable接口被设计出来的 目的就是为了抽象出writeObject和readObject这两个方法,但是目前这个接口使用的并不多。
Serializable VS Externalizable