JAVA序列化和反序列化的底层实现原理解析
序列化与反序列化的概念
序列化
序列化是指将对象转换成可传输的格式(例如字节码),并且可以在将来重新创建出与原对象完全相同的副本。序列化操作可以在网络上传输对象,或者将对象存储到本地磁盘上。
反序列化
反序列化是指将序列化后的数据流还原为原来的对象的操作。也就是说,反序列化能够重新创建出一个和已序列化的对象完全相同的对象实例。
序列化原理
序列化的实现
Java 序列化由 ObjectOutput 和 ObjectOutputStream 两部分组成。
具体来讲,ObjectOutput 在写出对象前会先写出该对象的 MetaData,即对象类型信息和属性值信息,然后使用 java.io.Serializable 接口中的 writeObject 方法将实例对象写入输出流中。
而 ObjectOutputStream 实现了 ObjectOutput 接口,在序列化时也采用了写出 MetaData 和 对象信息的方式,但在写出 MetaData 时,对同一类型的 MetaData 只创建一个。在写出对象时,该对象的类型信息和之前已写出的类型信息进行匹配,如果找到相同的类型信息,就使用之前的 MetaData,否则就新创建一个 MetaData 并记录下来。
序列化的缺点
Java 序列化存在以下缺点:
- 序列化后的数据量大,序列化后的码流默认为二进制编码,体积较大,不利于网络传输。
- 序列化运行效率较低,可能会影响系统的性能。
- 序列化后的数据不便于人阅读。
反序列化原理
反序列化可以使用 ObjectInput 和 ObjectInputStream 实现。
ObjectInput 接口有一个 readObject 方法,可以将序列化后的数据流反序列化成相应的对象。与序列化类似,反序列化时也需先读取定制化的 MetaData,根据 MetaData 对读入的二进制序列化数据进行解码,并转化为实例对象。
同时,ObjectInputStream 可以通过 setAllowList() 方法设置反序列化时允许读取的类白名单或黑名单,以防止序列化漏洞。
示例说明
以下是一个序列化示例:
public class User implements Serializable {
String name;
int age;
// 省略构造函数和 Getter/Setter 方法
public static void main(String[] args) throws IOException {
FileOutputStream fileOut = new FileOutputStream("user.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
User user = new User("Jack", 18);
out.writeObject(user);
out.close();
fileOut.close();
}
}
该代码片段将 User 对象序列化到 user.ser 中。
以下是一个反序列化示例:
public class User implements Serializable {
String name;
int age;
// 省略构造函数和 Getter/Setter 方法
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream fileIn = new FileInputStream("user.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
User user = (User) in.readObject();
in.close();
fileIn.close();
}
}
该代码片段从 user.ser 中读出序列化后的 User 对象,并将其反序列化为 Java 对象实例。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JAVA序列化和反序列化的底层实现原理解析 - Python技术站