Java序列化和transient的使用

9 篇文章 0 订阅

在了解序列化概念和原理前,我们先来了解一下为什么需要序列化。

为什么要序列化?
如果光看定义很难一下子理解序列化的意义,可以从另一个角度来理解一下什么是序列化。

应该知道游戏里有一个叫“存档”的功能,每次不想玩的时候可以把当前进度存档,下次有时间想玩的时候,直接载入存档就可以接着玩了,这样的好处是之前的游戏进度不会丢失。

创建的对象都是保存在内存中的,大家都知道内存的数据是短暂保留在缓存的,断电之后是会消失的,但是游戏经过手动存档之后就算你关机几天了,再次进入游戏读取存档,你会发现之前在游戏中创建的角色和装备都还在呢,这就很奇怪了,明明内存的数据断电就消失了,这是为什么?

存档的过程中就是将内存中的数据存储到电脑的硬盘中,硬盘的数据在关机断电后是不会丢失的(硬盘损坏数据丢失先不考虑)。这个过程就是对象的持久化,也就是我们今天要讲的对象序列化。对象的序列化逆过程就叫做反序列化,反序列化也很好理解就是将硬盘中的信息读取出来形成对象。

什么是序列化?

序列化是指将对象实例的状态存到存储的过程

反序列化是指将存储在存储中的对象状态装换成对象的过程

用更为抽象的概念来讲:

序列化:把对象转化为可传输的字节序列过程

反序列化:把字节序列还原为对象的过程

序列化的机制
序列化最终的目的是为了对象可以跨平台存储和进行网络传输,而我们进行跨平台存储和网络传输的方式就是 IO,而 IO 支持的数据格式就是字节数组。

把对象转成字节数组的时候就制定一种规则(序列化),那么我们从 IO 流里面读出数据的时候再以这种规则把对象还原回来(反序列化)。

常见序列化的方式
序列化只是定义了拆解对象的具体规则,那这种规则肯定也是多种多样的,比如现在常见的序列化方式有:JDK 原生、JSON、ProtoBuf、Hessian、Kryo等。

(1)JDK 原生

作为一个成熟的编程语言,JDK自带了序列化方法。只需要类实现了Serializable接口,就可以通过ObjectOutputStream类将对象变成byte[]字节数组。

JDK 序列化会把对象类的描述信息和所有的属性以及继承的元数据都序列化为字节流,所以会导致生成的字节流相对比较大。

另外,这种序列化方式是 JDK 自带的,因此不支持跨语言。

简单总结一下:JDK 原生的序列化方式生成的字节流比较大,也不支持跨语言,因此在实际项目和框架中用的都比较少。

(2)ProtoBuf

谷歌推出的,是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于通信协议、数据存储等。序列化后体积小,一般用于对传输性能有较高要求的系统。

(4)Hessian

Hessian 是一个轻量级的二进制 web service 协议,主要用于传输二进制数据。

在传输数据前 Hessian 支持将对象序列化成二进制流,相对于 JDK 原生序列化,Hessian序列化之后体积更小,性能更优。

(5)Kryo

Kryo 是一个 Java 序列化框架,号称 Java 最快的序列化框架。Kryo 在序列化速度上很有优势,底层依赖于字节码生成机制。

由于只能限定在 JVM 语言上,所以 Kryo 不支持跨语言使用。

(6)JSON

上面讲的几种序列化方式都是直接将对象变成二进制,也就是byte[]字节数组,这些方式都可以叫二进制方式。

JSON 序列化方式生成的是一串有规则的字符串,在可读性上要优于上面几种方式,但是在体积上就没什么优势了。

另外 JSON 是有规则的字符串,不跟任何编程语言绑定,天然上就具备了跨平台。

总结一下:JSON 可读性强,支持跨平台,体积稍微逊色。

JSON 序列化常见的框架有:

fastJSON、Jackson、Gson 等。

序列化技术的选型
上面列举的这些序列化技术各有优缺点,不能简单地说哪一种就是最好的,不然也不会有这么多序列化技术共存了。

既然有这么多序列化技术可供选择,那在实际项目中如何选型呢?

我认为需要结合具体的项目来看,比较技术是服务于业务的。你可以从下面这几个因素来考虑:

(1)协议是否支持跨平台

如果一个大的系统有好多种语言进行混合开发,那么就肯定不适合用有语言局限性的序列化协议,比如 JDK 原生、Kryo 这些只能用在 Java 语言范围下,你用 JDK 原生方式进行序列化,用其他语言是无法反序列化的。

(2)序列化的速度

如果序列化的频率非常高,那么选择序列化速度快的协议会为你的系统性能提升不少。

(3)序列化生成的体积

如果频繁的在网络中传输的数据那就需要数据越小越好,小的数据传输快,也不占带宽,也能整体提升系统的性能,因此序列化生成的体积就很关键了。

小结
(1)为什么我们要序列化?

因为我们需要将内存中的对象存储到媒介中,或者我们需要将一个对象通过网络传输到另外一个系统中。

(2)什么是序列化?

序列化就是把对象转化为可传输的字节序列过程;反序列化就是把字节序列还原为对象的过程。

(3)序列化的机制

序列化最终的目的是为了对象可以跨平台存储和进行网络传输,而我们进行跨平台存储和网络传输的方式就是 IO,而 IO 支持的数据格式就是字节数组。

将对象转成字节数组的时候需要制定一种规则,这种规则就是序列化机制。

(4)常见序列化的方式

现在常见的序列化方式有:JDK 原生、JSON、ProtoBuf、Hessian、Kryo等。

(5)序列化技术的选型

选型最重要的就是要考虑这三个方面:协议是否支持跨平台、序列化的速度、序列化生成的体积。

transient的用途及使用方法

1,用途
  我们知道,当一个对象实现了Serilizable接口,这个对象就可以被序列化,这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。而在开发过程中,我们可能要求:当对象被序列化时(写入字节序列到目标文件)时,有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。
 所以,transient的用途在于:阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。例如,当反序列化对象——数据流(例如,文件)可能不存在时,原因是你的对象中存在类型为java.io.InputStream的变量,序列化时这些变量引用的输入流无法被打开。

2,使用方法

序列化的时候,将不需要序列化的属性前添加关键字transient即可。

密码字段为null,说明被标记为transient的属性在对象被序列化的时候不会被保存。

使用小结:

1,一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
  2,transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
  3,被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
  对于第三点,加上static之后,依然能把姓名输出。这是因为:反序列化后类中static型变量name的值为当前JVM中对应static变量的值,这个值是JVM中的不是反序列化得出的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值