原文出处:未知java
Java的序列化机制是经过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,若是相同就认为是一致的,能够进行反序列化,不然就会出现序列化版本不一致的异常。
Eclipse中The serializable class XXXXXX does not declare a static final serialVersionUID field of type long出现这样的警告处理办法。
当采用程序的Add default Serial version ID修复时,Eclipse会加上:private static final long serialVersionUID = 1L;
当采用程序的Add generated Serial version ID修复时,Eclipse会加上:private static final long serialVersionUID = xxxxL;
其实这个问题出现的具体缘由是和序列化中的这个serialVersionUID有关。
serialVersionUID 用来代表类的不一样版本间的兼容性。有两种生成方式:
一个是默认的1L,好比:private static final long serialVersionUID = 1L;(对应修复方法1)
一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,好比:
private static final long serialVersionUID = xxxxL;(对应修复方法2)
在JDK中,能够利用JDK的bin目录下的serialver.exe工具产生这个serialVersionUID 的值,对于Test.class,执行命令:
serialver Test 这时JVM(java虚拟机)会生成一个哈希字段。
对比一下这个哈希字段的值与方法2中生成的字段值是同样的,可见,在CMD中使用serialver指令就是根据类名、接口名、成员方法及属性等来生成哈希字段的。
下面来讨论java类中为何须要重载 serialVersionUID 属性。
当两个进程在进行远程通讯时,彼此能够发送各类类型的数据。不管是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方须要把这个Java对象转换为字节序列,才能在网络上传送;接收方则须要把字节序列再恢复为Java对象。
把Java对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为Java对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,一般存放在一个文件中;
2) 在网络上传送对象的字节序列。
java.io.ObjectOutputStream表明对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把获得的字节序列写到一个目标输出流中。
java.io.ObjectInputStream表明对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自Serializable接口,实现Externalizable接口的类彻底由自身来控制序列化的行为,而仅实现Serializable接口的类能够采用默认的序列化方式 。
凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:private static final long serialVersionUID;
类的serialVersionUID的默认值彻底依赖于Java编译器的实现,对于同一个类,用不一样的Java编译器编译,有可能会致使不一样的serialVersionUID,也有可能相同。为了提升serialVersionUID的独立性和肯定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。显式地定义serialVersionUID有两种用途:
1)在某些场合,但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备相同的serialVersionUID;在某些场合,不但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备不一样的serialVersionUID。
2)当你序列化了一个类实例后,但愿更改一个字段或添加一个字段,不设置serialVersionUID,所作的任何更改都将致使没法反序化旧有实例,并在反序列化时抛出一个异常。若是你添加了serialVersionUID,在反序列旧有实例时,新添加或更改的字段值将设为初始化值(对象为null,基本类型为相应的初始默认值),字段被删除将不设置。
当系统不须要序列化类时,能够去掉这些警告,作以下设置:Window-->Preferences-->Java,将serializable class without serialVersionUID的设置由warning改成Ignore。而后Eclipse会从新编译程序,那些警告信息也就消失了。
struts架构下的网站常常出现javax.servlet.ServletException: BeanUtils.populate 错误,可是本地运行又一切正常,惟一以为可能产生问题的就是服务器上跑了好几个网站,都是同样的架构的,怀疑是否是web容器把几个项目之间的java类给共用了,考虑到不少类都定义了serialVersionUID字段,而后尝试删除了某个类的serialVersionUID,结果关于该类的操做就恢复正常了。网上简单查阅了一下资料,感受是tomcat把全部类串行化时候,因为咱们的几个项目不少java类都是复制粘贴的,因此致使了不少类的serialVersionUID都是同一个值,因此tomcat会把不一样项目的相同类名的类看成同一个类去处理,致使了这个奇怪的错误。
解决方案:
每一个项目同名的类serialVersionUID改成不同,不能直接的复制粘贴过来。web