天天看点

Java序列化

希望该文章,能够在你需要使用序列化进行编程的时候,提供借鉴或思路参考。

目录

什么是序列化?

怎么实现序列化?

一、实现serializable接口

二、实现externalizable接口

自定义序列化?

transient关键字

自定义readobject和writeobject方法

自定义writereplace方法

自定义readresolve方法

实现externalizable接口

序列化的注意事项

序列化的使用场景

一句话概括。序列化将对象的状态信息转换为可以存储或传输的形式的过程。而java序列化,就是指把java对象转换为“有序”字节序列的过程。相反的,把“有序”字节序列恢复为java对象的过程称之为反序列化。

怎么理解上面的描述呢?从序列化的定义的可以看出,序列化其实是一个用来保障存储和传输的机制,而其针对的对象,肯定就是那些不便存储和传输的信息,而这体现在java编程中,就是类的实例 —— 类对象。

上面提到的“有序”,它并不是真的有顺序,其实是比较抽象化的表达,以此来表达经过序列化处理的对象,能够通过反序列化恢复成原来的样子这样一个过程

举个例子,你要搬家了,家里有个大鞋架,因为鞋架太大了,不便存储和运输,于是你把鞋机拆散了,然后把拆解步骤记录下来,运输到新家后,你再根据步骤记录把零件组装成鞋架原来的样子。拆鞋架和组装鞋架其实就是序列化和反序列的过程,而你记录的那份拆解步骤,就是序列化协议。

定义一个类实现serializable接口:

实现<code>writeexternal</code>、<code>readexternal</code>方法
序列化和反序列化

正常的输出结果: <code>rectangle{width=6, length=8}</code> 当实现externalizable接口,没有对<code>writeexternal</code>和<code>readexternal</code>重写时,结果如下 <code>rectangle{width=0, length=0}</code> 也就是说的,实现externalizable接口,需要自己实现序列化和反序列逻辑,编程人员用比较高的灵活度,这点在接下来的自定义序列化会讲到

由<code>transient</code>关键字修饰的成员的变量,序列化时将被忽略。该方法决定变量是否序列化。

该自定义方法级别最低,当使用的下面的任一方法时,<code>transient</code>关键字将失效。换句话说,使用下面各方法进行序列化自定义,那么transient修饰的变量同样会被序列化。

通过的类中自定义<code>readobject</code>和<code>writeobject</code>方法,可以控制该类的序列化和反序列化逻辑,jvm在进行序列化的时候会自动调用<code>readobject</code>方法,反序列化调用<code>writeobject</code>。

<code>writereplace</code>方法没有入参,用于改变序列化对象的类型,且会使用默认的序列化机。也就是说,上面提到的自定义readobject和writeobject方法都将失效。以下为实例:

相应的,在进行反序列化的时候,就应该使用新的类型进行接收,如该例子,应该用<code>list&lt;object&gt;</code>接收反序列化对象。

<code>readresolve</code>方法用于替换反序列化出来的对象,该方法同样没有入参。

由于没发拿到序列化的信息,因此常用来控制单例模式下,反序列化出来的对象为原先的单例对象,以维护单例模式中反序列化对象的单一性。

这个已经在上面实例化方式中有所提及。实现该接口必须强制实现<code>writeexternal</code>和<code>readexternal</code> 两个方法如下:

该效果等同于上面实现serializable接口,然后自定义<code>readobject</code>和<code>writeobject</code>f方法

serialversionuid 序列化版本号

用来区分需要序列化类的版本。假如序列化的类中发生了变量的修改,那么该版本号一般也要跟着修改,才能够在反序列化的时候得到对应版本的类对象,否则会抛出<code>invalidclassexception</code>异常

序列化与类的初始化一样,是的一个递归的过程。

当一个类实现了序列化接口,该类的成员除了基本类型和string类型之外,其他的引用类型也必须是可序列化的;否则会抛<code>notserializableexception</code>异常

同一对象多次序列化只会序列化一次

如果程序对同一个对象有多次序列化,那么只会在第一次进行序列化,后续实际上是返回一个编号进行区分

反序列化的顺序与序列化时的顺序一致,类似队列模型

讲了这么多,那序列化到底用在什么地方呢?

由jvm的内存结构相关知识我们可以知道,java对象都被保存在堆内存中。在jvm处于运行状态的时候,我们能够对对象的进行复用。但一旦jvm生命周期结束,相关对象也随之被回收。也就是说的,如果希望在jvm停止后还能够拿到某些对象,这时候就需要用到java的序列化。

因此大概由以下几种场景会使用到java的序列化

当你想把的内存中的对象状态保存到一个文件中或者数据库中时候; 当你想用套接字在网络上传送对象的时候; 当你想通过rmi(远程方法调用)传输对象的时候;