序列化与反序列化
如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,这些场景都需要用到序列化。
简单来说:
- 序列化:将数据结构或对象转换成二进制字节流的过程
- 反序列化:将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程
下面是序列化和反序列化常见应用场景:
- 对象在进行网络传输(比如远程方法调用 RPC 的时候)之前需要先被序列化,接收到序列化的对象之后需要再进行反序列化;
- 将对象存储到文件之前需要进行序列化,将对象从文件中读取出来需要进行反序列化;
- 将对象存储到数据库(如 Redis)之前需要用到序列化,将对象从缓存数据库中读取出来需要反序列化;
- 将对象存储到内存之前需要进行序列化,从内存中读取出来之后需要进行反序列化。
序列化是对对象进行的,而不是对类进行的。
在面向对象编程中,类定义了一组属性和方法,这些属性和方法描述了属于该类的对象共有的特征和行为。而对象是类的一个实例,它具有具体的属性值,并可以执行由类定义的方法。
序列化的目标是将对象的状态(即属性值)转换为一种可以存储或传输的形式。这意味着序列化过程会捕捉对象当前的属性值,并将其转换为一种持久化格式(如文本文件、二进制文件等),以便可以在不同的系统之间传输或在将来某个时刻恢复对象的状态。
当对象被序列化时,以下会发生:
- 对象的属性值被转换为一种可以持久化的格式。
- 对象的方法定义不会被序列化,因为这些方法是与类绑定的,而不是对象的组成部分。
当对象被反序列化时,以下会发生:
- 根据存储或传输的格式,对象的状态被恢复。
- 必须在目标环境中定义了相同的类,以便可以创建对象并使其具有序列化时的方法。
总结一下:
- 序列化对象:将对象的状态(属性值)转换为可以持久化或传输的格式。
- 不序列化类定义:类定义(包括方法)不在序列化过程中传输,而是需要在目标环境中预先定义好。
简而言之,序列化通常涉及以下步骤:
- 将对象的状态(属性值)转换为一种可以存储或传输的格式(例如 JSON、XML 或二进制流)。
- 当需要使用对象时,从存储的格式中恢复对象的状态,并在目标环境中重建对象。
- 目标环境必须有相同类的定义,以便可以正确地使用序列化对象的方法。
举个例子,假设我们有一个名为 Person
的类,它有一个名为 sayHello
的方法。当我们序列化一个 Person
对象时,序列化过程只会保存该对象的属性(例如名字、年龄等),而不会保存 sayHello
方法的定义。当这个序列化的对象在另一个环境中被反序列化时,该环境需要有 Person
类的定义,包括 sayHello
方法,这样反序列化的对象才能正常使用该方法。
在面向对象编程中,方法定义通常是与类绑定在一起的,并不是通过序列化过程单独传输的。当你序列化一个对象时,你通常只传输该对象的状态信息(即对象的属性或字段的值),而不是它的行为(即方法)。
如果需要在网络中传输对象及其行为,通常有以下几种处理方式:
-
远程过程调用 (RPC) 或者 Web 服务:
- 在这种方法中,客户端向服务器发送请求来调用特定的方法。服务器端实现该方法并返回结果给客户端。这样,实际上是方法调用的结果被序列化和传输,而不是方法本身。
-
代理模式:
- 客户端和服务器之间可以通过代理对象来实现方法调用。代理对象在客户端模拟了远程对象的行为,而实际的方法调用则通过网络进行。
-
序列化可执行代码:
- 在某些情况下,可以序列化可执行代码(例如使用 Java 的
SerializedLambda
或其他语言中的类似机制)。但这通常是高级用例,且需要特别注意安全性问题。
- 在某些情况下,可以序列化可执行代码(例如使用 Java 的
-
动态语言的序列化:
- 在一些动态语言中,可能支持序列化方法定义,但这样做可能会带来安全风险和性能开销。
-
代码共享:
- 如果客户端和服务端共享相同的代码库,则不需要传输方法定义,因为双方都已具备相同的方法实现。
总结来说,方法定义通常不会作为序列化的一部分直接传输。相反,通常会采用上述方法之一来实现远程对象的行为调用。这些方法涉及的是方法调用的逻辑而非方法本身的序列化。
对于不想进行序列化的变量,使用 transient
关键字修饰。
transient
关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient
修饰的变量值不会被持久化和恢复。
关于 transient
还有几点注意:
transient
只能修饰变量,不能修饰类和方法。transient
修饰的变量,在反序列化后变量值将会被置成类型的默认值。例如,如果是修饰int
类型,那么反序列后结果就是0
。static
变量因为不属于任何对象(Object),所以无论有没有transient
关键字修饰,均不会被序列化。