java序列化和序列化ID的作用

谈到java序列化其实大家都能说出一二, java对象序列化的意思就是将对象的状态转化成字节流,以后可以通过这些值再生成相同状态的对象。对象序列化是对象持久化的一种实现方法,它是将对象的属性和方法转化为一种序列化的形式用于存储和传输。反序列化当然就是对对象的重建。

为什么序列化不是默认添加

开门见山,

其中最大的问题是对象的引用

假如我有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化

{ A a = new A(); B b = new B(); }

,这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b,接下来我们想将它们写入到磁盘的一个文件中去,就在写入文件时出现了问题!

因为对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时

内存分配了三个空间,而对象a同时在内存中存在两份。

这样的问题会很多,必须对a进行修改等操作,需要维护每一份的拷贝来达到数据的一致性。很大程度上浪费空间和影响性能。

不是默认序列化很重要的一个原因就是为了安全,java的类安全机制是做的很好的.

对于一个你要传输的对象,比如写到文件,或者进行rmi传输等等,在传输的过程中,
这个对象的private等域是不受保护的.

还有就是一些资源分配的问题,比如thread,序列化是很难对他重新分配资源,

所以并非所有的类都可以序列化.

同时添加序列化,会进行一系列的比较操作,可参考序列化机制,也会占资源,所以不需要流传输的就大可不必序列化。

序列化的漏洞

如果Java应用对用户输入,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就有可能带来任意代码执行。

所以这个问题的根源在于类ObjectInputStream在反序列化时,没有对生成的对象的类型做限制;假若反序列化可以设置Java类型的白名单,那么问题的影响就小了很多。

序列化ID的作用

序列化ID起着关键的作用,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。

序列化机制

  • 1.保存到磁盘的所有对象都获得一个序列号(1, 2, 3等等)
  • 2.当要反序列化保存一个对象时,先检查该对象是否被保存了。
  • 3.如果以前保存过,只需写入"与已经保存的类具有相同序列号的对象"的一样的标记就可,否则,保存该对象。

将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流

推荐阅读更多精彩内容