java 序列化理解_Java序列化的相关认知

序列化相关认识

序列化的意义

?将内存中的对象,以字节码形式存储起来,等待用时反序列化回来,主要是IO操作,可以有更长的生命周期和跨项目性质的作用。

序列化和反序列化

序列化:将对象的信息转化为字节码的形式存储或传输的过程,称为序列化。

public class Person{

private String name;

public void setName(String name){

this.name = name

}

public String getName(){

return name;

}

}

Person person = new Person();

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("person.txt")));

oos.writeObject(person);

?反序列化:序列化的逆向过程,将字节码读取转化为对象的过程,称为反序列化。

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("person.txt")));

Person person = (Person) ois.readObject();

如何实现序列化

在java中只要一个类实现了java.io.Serializable 接口,那么它就可以被序列化

基于JDK序列化方式实现

JDK提供了Java对象的序列化方式,主要通过输出流 java.io.ObjectOutputStream 和 对象输入流 java.io.ObjectInputStream 来实现。其中,被序列化的对象需要 实现java.io.Serializable接口

序列化的问题

序列化的实现方式优劣指标:

序列化后的数据大小

序列化操作的速度以及系统开销

Java序列化的缺点:

序列化后的数据比较大

其他语言无法识别和对接

深入理解序列化

JDK序列化中serialVersionUID的作用:

Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM 会把传来的字节流中的 serialVersionUID与本地相应实体类的 serialVersionUID 进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException

如果没有为指定的 class 配置 serialVersionUID,那么 java 编译器会自动给这个 class 进行一个摘要算法,类似于指纹算法,只要这个文件有任何改动,得到的 UID 就会截然不同的,可以保证在这么多类中,这个编号是唯一的

serialVersionUID生成规则

默认的1L,比如:private static final long serialVersionUID = 1L;

根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段

当 实 现 java.io.Serializable 接 口 的 类 没 有 显 式 地 定 义 一 个serialVersionUID 变量时候,Java 序列化机制会根据编译的 Class 自动

生成一个 serialVersionUID 作序列化版本比较用,这种情况下,如果Class 文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialVersionUID 也不会变化的。

静态变量序列化

?序列化时并不保存静态变量,序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量。

父类序列化问题

?子类实现了Serializable接口,父类未实现,在子类中调用父类属性赋值,序列化过程中出现的情况

若父类未实现Serializable,在反序列化中,无法获取赋值给父类属性值。

父类实现Serializable,则子类无需再次实现Serializable接口,自动实现序列化

如果一个可序列化的类的成员不是基本类型,也不是String类型,那这个引用类型也必须是可序列化的;否则,会导致此类不能序列化。

Transient关键字

?使用transient修饰的属性,java序列化时,会忽略掉此字段,所以反序列化出的对象,被transient修饰的属性是默认值。对于引用类型,值是null;基本类型,值是0;boolean类型,值是false,初始值。

重复序列化问题

?Java序列化同一对象,并不会将此对象序列化多次得到多个对象

?Java序列化算法:

所有保存到磁盘的对象都有一个序列化编码号

当程序试图序列化一个对象时,会先检查此对象是否已经序列化过,只有此对象从未(在此虚拟机)被序列化过,才会将此对象序列化为字节序列输出。

如果此对象已经序列化过,则直接输出编号即可。当写入文件为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,上面增加的5字节的存储空间就是新增 引用和一些控制信息的空间。反序列化时,恢复引用关系,该存储规则极大的节省了存储空间。

可以作为深度克隆

?Java的拷贝一般都是实现Cloneable接口,并重写clone方法进行拷贝操作,主要是对象表皮复制了一份,内部属性的对象引用未改变。

属性类型是基本数据类型或者String字符串类型不影响。

?针对拷贝时对象属性引用问题有几种解决方式

可以在对象属性字段的对象也加上实现Cloneable接口调用clone(比较麻烦),如下:

@Override

public Object clone() throws CloneNotSupportedException {

Teacher teacher = (Teacher) super.clone();

//把引用类型的变量在克隆一份

teacher.setStudent((Student) teacher.getStudent().clone());

return teacher;

}

可以利用序列化的方式,将对象转化为字节流,再转化回对象,做个中转(可能稍微有点麻烦,但非常实用),如下:

public Object copyObject(Object object) throws IOException, ClassNotFoundException {

//创建字节数组输出流将索要拷贝对象写入

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

//创建对象输出流将字节数组输出流传入直接将对象写入字节输出流

ObjectOutputStream objectOutputStrea = new ObjectOutputStream(byteArrayOutputStream);

objectOutputStrea.writeObject(object);

//将刚写入的输出流转化为字节数组传入字节数组输入流

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

//对象输入流包装读取为一个对象

ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);

return objectInputStream.readObject();

}

还有可以使用JSON的方式,先将对象转为json,再转回对象,这是不错的想法

常见的序列化技术

Java JDK序列化:简单方便,但是不能跨语言,以及数据量大

XML序列化:可能是通用、阅读好吧(个人不喜欢),缺点比较明显,效率低,数据大

JSON序列化:比较轻量级,数据量小,阅读性高,比较通用(个人比较推荐),主要有(Jackson、FastJson、GSON等)

Hessian 序列化框架:Hessian是一个支持跨语言传输的二进制序列化协议,相对于Java默认的序列化机制来说,Hessian具有更好的性能和易用性,而且支持对重不同的语言,实际上Dubbo采用的就是Hessian序列化来实现,只不过Dubbo对Hessian进行重构,性能更高

Protobuf 序列化框架:个人认为这个和JSON没啥太大差别,只是比JSON更加浓缩,数据格式简洁、量少、但是对对象的支持不太好,若是有解析框架都好说,主要注重RPC传输的数据格式。

序列化速度快的原因:编码 / 解码 方式简单(只需要简单的数学运算 = 位移等等),采用特殊方式标记,更加紧凑

?

原文:https://www.cnblogs.com/zhouguanglin/p/14429031.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值