序列化是指将对象转换为可存储或可传输的格式的过程。在计算机科学中,序列化常用于在进程之间传输数据,或将数据存储到文件或数据库中。
一、实体类序列化的作用
在Java中,实体类对象是存放在内存中的,而我们需要将其保存到数据库中或进行网络传输时,则需要将实体类序列化为字节流。
例如,下面是一个用户实体类的定义:
public class User { private Long id; private String name; private String email; // 构造函数和get/set方法省略 }
将用户实体类序列化为字节流的示例代码如下:
User user = new User(1L, "Alice", "alice@example.com"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(user); byte[] bytes = bos.toByteArray(); out.close(); bos.close();
从字节流中反序列化为实体类对象的示例代码如下:
byte[] bytes = ...; // 从网络或文件中读取的字节流 ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream in = new ObjectInputStream(bis); User user = (User) in.readObject(); in.close(); bis.close();
二、序列化活动的概念
1. 序列化和反序列化过程
序列化是将对象转换为字节流的过程,而反序列化则是将字节流转换回原始对象的过程。
在Java中,序列化和反序列化可以通过实现Serializable接口来实现。例如:
public class User implements Serializable { ... }
当序列化一个实现Serializable接口的对象时,Java会保存对象的类名、类结构和对象数据等信息,以便在反序列化时使用。
2. 序列化协议
序列化协议是指序列化对象时规定的字节序、类型信息、字段顺序等规则。Java有自己的默认序列化协议,也可以使用其它协议,例如Google的Protocol Buffer。
默认情况下,Java使用的序列化协议会将对象数据编码为字节流,并保存对象的完整类名、字段名称和类型信息等。这种序列化方式会占用大量空间,并且对于字段名称的修改、添加或删除等操作会造成反序列化失败。
因此,为了提高序列化的效率和可靠性,我们可以使用优化过的序列化协议,例如Google的Protocol Buffer或Facebook的Thrift。
3. 序列化版本号
序列化版本号是一个32位的整数,用于标识序列化对象的版本号。当对象发生变化时,我们需要更新版本号,以便反序列化时能够识别出不同版本的对象。
在Java中,可以使用serialVersionUID属性来表示序列化对象的版本号。例如:
public class User implements Serializable { private static final long serialVersionUID = 1L; ... }
三、与序列化相关的其他概念
1. 反序列化漏洞
反序列化漏洞是指攻击者利用序列化和反序列化机制的漏洞,将恶意代码注入到反序列化的对象中,从而导致安全漏洞。这种漏洞通常会导致远程代码执行、拒绝服务、数据泄露等严重后果。
为了防止反序列化漏洞,我们需要使用白名单机制来限制反序列化的类和对象,或使用安全的序列化协议。
2. JSON序列化
JSON是一种轻量级的数据交换格式,能够表示复杂的数据结构,并且具有良好的可读性和易用性。在前后端数据传输和API调用中,JSON已经成为了一种标准的编码方式。
在Java中,我们可以使用Jackson、Gson等库来将Java对象序列化为JSON字符串,或将JSON字符串反序列化为Java对象。
例如,将User对象序列化为JSON字符串的示例代码如下:
User user = new User(1L, "Alice", "alice@example.com"); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(user);
从JSON字符串反序列化为User对象的示例代码如下:
String json = ...; // 从前端或API获取的JSON字符串 ObjectMapper mapper = new ObjectMapper(); User user = mapper.readValue(json, User.class);
3. XML序列化
XML是一种用于数据交换的标记语言,具有良好的可扩展性和可读性。在Java中,我们可以使用JAXB、Xstream等库将Java对象序列化为XML文件或字符串,或将XML字符串反序列化为Java对象。
例如,将User对象序列化为XML文件的示例代码如下:
User user = new User(1L, "Alice", "alice@example.com"); JAXBContext context = JAXBContext.newInstance(User.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(user, new File("user.xml"));
从XML文件中反序列化为User对象的示例代码如下:
File file = new File("user.xml"); // 从文件中读取XML数据 JAXBContext context = JAXBContext.newInstance(User.class); Unmarshaller unmarshaller = context.createUnmarshaller(); User user = (User) unmarshaller.unmarshal(file);
4. 序列化框架
随着业务系统的复杂度不断提高,我们需要处理更加复杂的数据结构和业务逻辑。因此,序列化框架成为了一个重要的工具和组件库。
目前流行的Java序列化框架包括Kryo、FST、Hessian、Avro等。这些框架具有高效、可扩展、易用等特点,并且可以适应不同的业务场景和性能需求。
例如,使用Kryo将User对象序列化为字节流的示例代码如下:
User user = new User(1L, "Alice", "alice@example.com"); Kryo kryo = new Kryo(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); Output output = new Output(bos); kryo.writeObject(output, user); output.close(); byte[] bytes = bos.toByteArray(); bos.close();
从字节流反序列化为User对象的示例代码如下:
byte[] bytes = ...; // 从网络或文件中读取的字节流 Kryo kryo = new Kryo(); Input input = new Input(bytes); User user = kryo.readObject(input, User.class); input.close();