`
lokki
  • 浏览: 58822 次
  • 来自: ...
社区版块
存档分类
最新评论

Serializable、serialVersionUID和serialver

    博客分类:
  • java
阅读更多
以前创建的,也有公布过给几千人,先发上来,有空再整理格式

'''Serializable、serialVersionUID和serialver'''

= 一些要求 =
(1)通过网络传输的对象,必须实现Serializable接口,或者父类已经实现序列化接口。

(2)网络传输对象封装太多层次的父类不太好,或者说在interface上用父类定义,然后将子类实例传递给网络另一端的应用可能没这个jar包/class,反序列化不了的。另一可能情况,动态代理接口InvocationHandler invoke(Object proxy, Method method, Object[] args),传进时,method的参数定义匹配interface上的method参数定义,比如是父类,从args获取的class是子类,如果某种rpc技术处理不当(HSF还算可用),或无从识别,困扰的是使用者。

(3)网络接口上的参数、返回值类型、会抛出的异常类,都要实现序列化接口。包括层层里面装着的内容,父类(比较少人对这field推敲private/protected,父类可能有直接被使用的时候)。

(4)ArrayList.subList()返回的List实现类是内部类型,不能序列化的,通过网络传输会出错。

(5)<font color="#ff0000">网络对象第一次上线使用时,就要设定serialVersionUID,不要不顾编译警告</font>

网络对象的匹配,除了靠类名,还靠serialVersionUID,serialVersionUID在《Java语言规范》有固定算法,跟各field的定义相关,如果没有显式赋值,虽然看不见,但会底下会默认算出一个进行网络传输。

如果没有显式赋值,也在你看不见觉察不到的情况下,在你增减了field/修改了定义的情况下,serialVersionUID已被改变,这时网络两端就对接不上而悲剧了。没定义serialVersionUID,而又发生了serialVersionUID变化,网络两端只有所有机器都停掉,并且先后起有顺序时,才能不出丝毫差错。

(6)网络传输对象要有无参构造器,因为机器系统是不知道传什么内容给有参构造器进行实例化,无参构造器不是public都没关系。没定义无参构造器,有些序列化方式会在底下生成无参构造器的方式才能解决问题。

(7)网络传输最好不要用enum类型,太强耦合,从网络一端传到另一端,对方可能还是旧版本而识别不了。[http://hi.baidu.com/yl_ty/blog/item/3a7f350b5710191495ca6bd2.html 别人文章里有enum的序列化说明]
[http://www.cnblogs.com/diyunpeng/archive/2011/03/17/1987121.html 以及这篇的末尾]

(8)有的人喜欢用1L作为serialVersionUID,但不知道是否是通配值,一开始就有赋值肯定没错,0L对于java enum的序列化有特殊意义。

(9)看看HashMap、Date的源代码,不需通过网络传输的field用transient定义,然后实现writeObject等方法。不是所有场合都识别Externalizable,或许都要此场合特别支持Externalizable才行。

(10)有些系列化格式,遇到反序列化不了的类,会反序列化成Map,但会在使用时遇到class cast异常。

(11)不用抛客户端没有jar的异常类到客户端

(12)同一应用不要有同package同名类,即使隐藏在同名/不同名/不同版本的jar中。

(13)远程调用、notify、放入tair、本地保存,或许都需要经过序列化,虽然让你透明地使用网络/感觉不到。

(14)不要序列化大数据对象/十分复杂对象,一般long/int/String/Map/List/Array等常见类组成的对象就已能解决问题,最好不要在本应用的业务接口传递/返回另一人主导业务/结构的对象。
不是建议不要用ArrayList,只是要注意ArrayList经过网络后可能顺序不一样。两需一一对应的List,经过网络后不一定一一对应。List中有零星的null,可能会给别人造成麻烦。

= 先前没设定serialVersionUID,怎么办 =
由于没赋值serialVersionUID 只是警告,不是错误,造成先前没留意设定serialVersionUID,<font color="#ff0000">网络两端上线运行一段时间也感觉正常</font>。
如果再增减修改field,没赋值好serialVersionUID,网络两端就不匹配。

解决步骤如下:serialver命令在jdk/bin目录,用于算出某类的serialVersionUID。

(1)用旧代码的类生成 serialVersionUID:
serialver -classpath myjar-1.0.jar com.taobao.myjar.MyDO

输出结果类似:com.taobao.myjar.MyDO: static final long serialVersionUID = 2075130392266935898L;

(2)然后将这行代码复制到新代码上。

即是说,
如果要在序列化DO里增加/变化field,又要和旧的没有serialVersionUID的DO作兼容,可以用serialver算出旧DO的serialVersionUID,赋值给变化了的DO,这样两边就匹配了

其它说明:

(3)可能会造成两边不匹配的改动,最好是搭车在两端都停机发布时。如果按以上方法做,应该不需出现如此情形。

(4)如果其它field不变动时,增加由serialver自动生成serialVersionUID并不会造成不匹配的情况。

(5)相同的代码,用serialver生成的和用eclipse界面生成的,是一样的。
分享到:
评论
2 楼 tuspark 2015-07-12  
这篇《serialversionuId作用》解释的更清楚,更有通俗易懂。
1 楼 tuspark 2015-07-12  
这篇[url= http://swiftlet.net/archives/1268]《serialversionuId作用》[/url]解释的更清楚,更有通俗易懂。

相关推荐

Global site tag (gtag.js) - Google Analytics