java序列化

前言:

序列化通俗点说就是对象------>字节流的过程,为什么要序列化呢?在分布式环境下,无论是何种数据,都会以二进制序列的形式在网络上传输。序列化是一种将对象以一连串的字节描述的过程,用于解决在对象流进行读写操作时所引发的问题。序列化可以将对象的状态写在流里进行网络传输,或保存在文件、数据库里,并在需要时把该流读取出来重新构造一个相同的对象。

java序列化原理:

java序列化对象的信息包括:类元数据的描述、类的属性、父类信息以及属性域的值,java将这些信息分成了:序列化头信息、类的描述以及属性域值的部分。jdk中其序列化算法的基本步骤包括了一下的3个部分:

1>输出序列化的头部信息,包括了标识序列化协议的幻数。(补充一:幻数就是具体的数值,并不能真实的反应数字所代表的含义,代码中经常会出现这样的数值,通常因为这些数字并不能直观的反应其实际的业务含义,通常会通过定义枚举和定义宏来提高代码的可读性)

2>按照子类到父类的顺序递归的输出类的描述信息,直到不再有父类信息位置。类描述信息按照类元数据、类属性信息的顺序写入序列化流中。

3>按照由父类到子类的顺序,递归的输出对象域的实际数据值。而对象的属性信息是按照基本数据类型到JAVA对象类型的顺序写入序列化流中,其中JAVA对象类型的属性会按照以上的步骤重新开始递归输出,知道不再存在JAVA对象类的属性。


java序列化的实现方法:

实现java.io.Serializablejava.io.Serializable接口,该接口没有方法,只是一种标记。

   如果想序列化一个对象,创建一个outPutStream,然后把它嵌入ObjectOutPutStream中,这是就可以调用writeObject()方法把对象写入OutPutStream中,writeObject()方法负责吸入特定类的状态,以便在readObject()方法可以还原它,通过调用out.defaultWriteObject()可以调用保存object的字段的默认机制。

读的时候,需要把IntputStream嵌入到objectInputStream里面,然后再调用readObject()方法,不过这样读出来的,仅仅是一个对象的一个引用。因此在对对象使用之前还需要先下传,readObject()方法负责从流中读取并还原心态,它可以调用in.defaultReadObject()来调用默认机制,以还原对象的非静态和非瞬态字段。

序列化存在的问题:

1.对于一个对象序列化,只保存对象的非静态成员变量,这里是包裹声明私有的成员变量,但是不能保存任何的成员方法和静态成员变量。

2.如果对象的成员变量也是一个对象,那么这个对象的数据成员变量也会被序列化。

3.如果一个可以被序列化的对象包含了不可序列化的对象的引用,那么整个序列化的操作都会失败,并不会存在部分成功的结果,并且会抛出NotSerializableException。我们可以将整个引用标记为tranSient,那么这个对象依然可以被序列化。(补充二:transient关键字:当对象被序列化时,transient阻止实例中那些用此关键字声明的变量持久化,当对象被反序列化进行重构时,这样的实例变量值不会被恢复)

序列化的作用(为什么要序列化)

保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。Java提供了一种比自己保存对象状态更好的机制,序列化。

serialVersionUID

序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致  InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终(final) 的 long 型字段)显式声明其自己的 serialVersionUID:

 ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

  如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值。不过,建议 所有可序列化类都显式声明 serialVersionUID 值,因为计算默认的 serialVersionUID对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private修饰符显示声明 serialVersionUID,原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值