Serializable

Posted xiaowater

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Serializable相关的知识,希望对你有一定的参考价值。

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。 

SerialVersionUid,简言之,其目的是序列化对象版本控制,有关各版本反序列化时是否兼容。如果在新版本中这个值修改了,新版本就不兼容旧版本,反序列化时会抛出InvalidClassException异常。如果修改较小,比如仅仅是增加了一个属性,我们希望向下兼容,老版本的数据都能保留,那就不用修改;如果我们删除了一个属性,或者更改了类的继承关系,必然不兼容旧数据,这时就应该手动更新版本号,即SerialVersionUid。

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

 

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。   

transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。  

2、什么情况下需要序列化?? 

a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候即持久化
b)当你想用套接字Socket在网络上传送对象的时候;
c)当你想通过RMI(Remote Method Invocation,远程方法调用)传输对象的时候;

6、相关注意事项

 

  • 序列化时,只对对象的状态进行保存,而不管对象的方法;
  • 当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
  • 当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
  • 并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:

 

 

  1. 安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输 等等,在序列 化进行传输的过程中,这个对象的private等域是不受保护的。
  2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是 没有必要这样实现。

 

 

当一个类的结构发生变化,需要改变serialVersionUID,以通知序列化机制此类发生了变化,不兼容原来的版本了!其实并不是只要类结构变化,就必须更改serialVersionUID,JAVA的序列化机制提供了部分变化的兼容机制,有如下几种: 

 

  • 添加新的属性 反序列时发现没有此属性,则会赋予该属性默认的类型值 
  • 添加 writeObject/readObject 方法 因为此方法是用于自定义序列化,不影响序列化 
  • 删除 writeObject/readObject 方法 同上原因 
  • 改变属性的访问权限(private protected package public) 
  • 将一个属性从static变为nonstatic 或者 transient 或者 nontransient 

 

如果你的类改动属于以上范围,默认的JAVA序列化机制可以保证兼容性,也就是说你不需要改动serialVersionUID值。

 

 

  1. Non Serializable Object : Memcached缓存对象时要求类对需实现Serializable这个接口,否则会抛出Non Serializable Object 
  2. Non-transient non-serializable instance field in Serializable class 意思是在序列化的类中有非序列化的对象,并且没有对非序列化对象标注Transient ,这样做的后果是这个类的实列不能被序列化。 
  3. 不重视序列号 如果我们的序列化仅仅是用作缓存的话,我们可以简单处理,只要改动了类结构,即修改serialVersionUID值,抛弃原先的序列化结果,重新生成! 

 

 

Externalizable继承于Serializable,当使用该接口时,序列化的细节需要由程序员去完成。如上所示的代码,由于writeExternal()与readExternal()方法未作任何处理,那么该序列化行为将不会保存/读取任何一个字段。这也就是为什么输出结果中所有字段的值均为空。

 
无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。
技术分享图片
 
Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。   
 
transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。  
影响序列化进程
  1. transient
  2. writeObject()/readObject()
  3. Externalizable
  4. readResolve

以上是关于Serializable的主要内容,如果未能解决你的问题,请参考以下文章