本篇文章给大家谈谈使Java运行时忽略serialVersionUID?,以及java忽略警告的知识点,同时本文还将给你拓展JavaprivatestaticfinallongserialVersio
本篇文章给大家谈谈使Java运行时忽略serialVersionUID?,以及java忽略警告的知识点,同时本文还将给你拓展Java private static final long serialVersionUID 作用、java serialVersionUID作用、Java serialVersionUID作用和生成、Java SerialVersionUID作用详解等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- 使Java运行时忽略serialVersionUID?(java忽略警告)
- Java private static final long serialVersionUID 作用
- java serialVersionUID作用
- Java serialVersionUID作用和生成
- Java SerialVersionUID作用详解
使Java运行时忽略serialVersionUID?(java忽略警告)
我必须使用大量未明确指定serialVersionUID的已编译Java类。由于它们的UID是由编译器任意生成的,因此即使实际的类定义匹配,许多需要序列化和反序列化的类最终也会导致异常。(当然,这是所有预期的行为。)
对我来说,返回并修复所有第3方代码是不切实际的。
因此,我的问题是:是否有任何方法可以使Java运行时 忽略 serialVersionUID中的差异,并且仅在结构上存在实际差异时才无法反序列化?
答案1
小编典典如果您有权访问代码库,则可以使用Ant的SerialVer任务来插入和修改serialVersionUID
可序列化类的源代码,并彻底解决此问题。
如果不能这样做,或者这不是一个选择(例如,如果您已经序列化了一些需要反序列化的对象),则一种解决方案是extendObjectInputStream
。增强其行为,以比较serialVersionUID
流描述符与serialVersionUID
该描述符表示的本地JVM中的类的类,并在不匹配的情况下使用本地类描述符。然后,只需使用此自定义类进行反序列化即可。这样的东西(此消息的信用):
import java.io.IOException;import java.io.InputStream;import java.io.InvalidClassException;import java.io.ObjectInputStream;import java.io.ObjectStreamClass;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class DecompressibleInputStream extends ObjectInputStream { private static Logger logger = LoggerFactory.getLogger(DecompressibleInputStream.class); public DecompressibleInputStream(InputStream in) throws IOException { super(in); } @Override protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { ObjectStreamClass resultClassDescriptor = super.readClassDescriptor(); // initially streams descriptor Class localClass; // the class in the local JVM that this descriptor represents. try { localClass = Class.forName(resultClassDescriptor.getName()); } catch (ClassNotFoundException e) { logger.error("No local class for " + resultClassDescriptor.getName(), e); return resultClassDescriptor; } ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass); if (localClassDescriptor != null) { // only if class implements serializable final long localSUID = localClassDescriptor.getSerialVersionUID(); final long streamSUID = resultClassDescriptor.getSerialVersionUID(); if (streamSUID != localSUID) { // check for serialVersionUID mismatch. final StringBuffer s = new StringBuffer("Overriding serialized class version mismatch: "); s.append("local serialVersionUID = ").append(localSUID); s.append(" stream serialVersionUID = ").append(streamSUID); Exception e = new InvalidClassException(s.toString()); logger.error("Potentially Fatal Deserialization Operation.", e); resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization } } return resultClassDescriptor; }}
Java private static final long serialVersionUID 作用
对象序列化 Serializable
一般情况下我们序列化对象的时候需要 implements Serializable 接口,然后就可以序列化了。序列化 称呼为 对象存档 更合适。但是 经常会看到 private static final long serialVersionUID = ***L
这样一句话 ,
import java.io.Serializable;
class DeepClone implements Serializable{
private static final long serialVersionUID = 1L;
/** * 利用序列化和反序列化进行对象的深拷贝 * @return * @throws Exception */
public Object deepClone() throws Exception{
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
如果你不添加serialVersionUID,那么Eclipse在会根据这个类的结构(成员变量,成员变量的个数等),生成一个hash值,然后将这个值作为serialVersionUID。
外网结束SerialVersionUID
SerialVersionUID is an ID which is stamped on object when it get serialized usually hashcode of object, you can use tool serialver to see serialVersionUID of a serialized object . SerialVersionUID is used for version control of object. you can specify serialVersionUID in your class file also. Consequence of not specifying serialVersionUID is that when you add or modify any field in class then already serialized class will not be able to recover because serialVersionUID generated for new class and for old serialized object will be different. Java serialization process relies on correct serialVersionUID for recovering state of serialized object and throws java.io.InvalidClassException in case of serialVersionUID mismatch.
SerialVersionUID,后面简称SUID,是当对象序列化时候你对象对应代码的一个标识类似与对象跟代码之间的K-V ,SUID的值常为该对象的hascode。你可以使用工具serialver查看一个序列化对象的SUID。SUID用于控制对象的版本。你也可以在类文件中指定SUID。不指定SUID的结果就是当你添加或者更改类的域并已经序列化类的时候,类是不能再恢复了,因为新的SUID和之前的SUID不同了。Java的序列化过程依赖于正确的SUID来反序列化已经序列化的对象,如果SUID不匹配,那么就会抛 java.io.InvalidClassException 异常了。
An SUID is not a hash of the object, but a hash of its originating class. If the class is updated, for example with different fields, the SUID can change. You have four (at least) possible courses of action:-
1: Leave out the SUID. This tells the runtime that there are no differences between versions of classes when serialising and deserialising.
2: Always write a default SUID, which looks like the heading of this thread. That tells the JVM that all versions with this SUID count as the same version.
3: Copy an SUID from a previous version of the class. That tells the runtime that this version and the version the SUID came from are to be treated as the same version.
4: Use a generated SUID for each version of the class. If the SUID is different in a new version of the class, that tells the runtime that the two versions are different and serialised instances of the old class cannot be deserialised as instances of the new class.
UID不是一个对象的哈希值(翻译错了,公司一个牛逼同事提醒了!),是源类的哈希值。如果类更新,例如域的改变,SUID会变化,这里有4个步骤:
- 忽略SUID,相当于运行期间类的版本上的序列化和反序列上面没有差异。
- 写一个默认的SUID,这就好像线程头部。告诉JVM所有版本中有着同样SUID的都是同一个版本。
- 复制之前版本类的SUID。运行期间这个版本和之前版本是一样的版本。
- 使用类每个版本生成的SUID。如果SUID与新版本的类不同,那么运行期间两个版本是不同的,并且老版本类序列化后的实例并不可以反序列成新的类的实例,说白了如果我们对类中属性进行了增加修改或删除,那么此时SUID要变的,因为 序列化跟反序列化要保持一致。
java serialVersionUID作用
serialVersionUID作用:
序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。
有两种生成方式:
一个是默认的1L,比如:private static final long serialVersionUID = 1L;
一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:
private static final long serialVersionUID = xxxxL;
1、没有显示指定序列号
对象序列化时,如果没有指定序列号,JVM会为我们自动产生一个值,但这个值和编译器的实现相关,之后你的类Serialized存到硬盘上面后,可是后来你却更改了类别的field(增加或减少或改名),当你Deserialize时,编译器会根据类最新的结构生成一个序列号,跟序列化前的序列号比较,不相同就会出现InvalidClassException的,这样就会造成不兼容性的问题。
2、显示指定序列号
显示指定了序列号,改变类field,当你Deserialize时它就会将不一样的field以type的预设值Deserialize
Java serialVersionUID作用和生成
序列化和反序列化
Java是面向对象的语言,与其他语言进行交互(比如与前端js进行http通信),需要把对象转化成一种通用的格式比如json(前端显然不认识Java对象),从对象到json字符串的转换,就是序列化的过程,反过来,从json字符串转换成Java对象,就是反序列化的过程。
serialVersionUID是什么
反序列化的过程,需要从一个json字符串生成一个Java对象。典型的如下:
Gson gson = new Gson();
Request req = gson.fromJson("request string", Request.class)
这时候会有问题,需要验证输入的json字符串是否是从当前的Request这个类序列化过去的,serialVersionUID就是用来干这个的。当序列化的时候的serialVersionUID与反序列化的时候的serialVersionUID不一致的时候,会跑出InvalidCalssException。
如果没有显式地定义一个serialVersionUID,那么Java会默认根据类信息计算一个serivalVersionUID出来。
The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender’s class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named “serialVersionUID” that must be static, final, and of type long:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class–serialVersionUID fields are not useful as inherited members.
如何生成
Intellij IDEA可以自动为serializable的类生成一个serialVersionUID。
Preferences - Inspection - Serializable class without ‘serialVersionUID’ 勾选。
这样,如果没有申明serialVersionUID属性,编辑器就会给出提示,按alt + Enter 可以快速生成。
这样在没有serialVersionUID的类中,可以自动根据提示生成serialVersionUID了。
Java SerialVersionUID作用详解
这篇文章主要介绍了Java SerialVersionUID作用详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
问题1:Serializable是什么
首先,说说Serializable是实现java将内存中的类存储至硬盘中而使用的
一个类使用了Serializalbe接口,在序列化到文件时,会有一个SerialVersionUID。
这个东东是用于对类进行版本控制的。
首先看Person类清单:
=====
import java.io.Serializable; public class Person implements Serializable { //如果没有指定serialVersionUID,系统会自动生成一个 private static final long serialVersionUID = 1L; private String name; //添加这么一个成员变量 private String address; //序列化后如果之前版本没有,就为null public String getName() { // int a = 100; // for(int i=0;i
===== 然后是测试类清单 =====
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; /** * if Object implements Serializable without Uid, * system will automatically give this object a uid by algorithm * @author v11 * @date 2014年9月18日 * @version 1.0 */ public class WhySerialversionUID { public static void objectToFile(Object obj,String fileName) throws Exception{ ObjectOutputStream oo = new ObjectOutputStream( new FileOutputStream( fileName)); oo.writeObject(obj); oo.close(); } public static Object getobjectFromFile(String fileName) throws Exception { ObjectInputStream oi = new ObjectInputStream( new FileInputStream( fileName)); Person crab_back = (Person) oi.readobject(); oi.close(); return crab_back; } public static void main(String[] args) throws Exception { String fileName = "crab_file" ; //文件名 // 这里是把对象序列化到文件 Person crab = new Person(); crab.setName( "Mr.Crab" ); //储存到文件中 //objectToFile(crab,fileName); // 这里是把对象序列化到文件,我们先注释掉,一会儿用 Person crabBack = (Person) getobjectFromFile(fileName); //Dog crabBack = (Dog) getobjectFromFile(fileName); System.out.println( "Hi, My name is " + crabBack.getName()); } }
=====
1.对于Person类中,将变量 address和SerialVersionUID注释掉,存储到文件,并读出。显示正常
2.将变量address还原,读取原来存储的文件,显示异常。抛出错误 InvalidClassException。
原因如下:
因为我们没有指定SerialVersionUID,因此系统自动生成了一个serialVersionUID(这个是根据类名,变量名,方法名)生成的
但是改动后的Person中变量名有变动,于是这个UID就不一样了,对于版本控制就无法读取。
所以,大家在很多代码里看到把UID设置为1L,就是Person代码中那样。
将Person代码UID设置为1L,再重复上述步骤,不报错。那么就意味着如果你选择将UID设置为1L,就是选择了兼容类的版本不一致。
PS:为什么说自动生成的 serialVersionUID是根据 类名,变量名,方法名,因为当你在原有的类的方法内进行添加内容,并不是对最后系统生成的UID造成影响,即不会抛出错误
问题2:所有类都设置为1L,是否有不良影响,不同类会不会冲突
public class Dog implements Serializable{ private static final long serialVersionUID = 1L; private String name; public String getName() { return name; } public void setName(String name) { this .name = name; } }
新定义Dog类如上,将测试类代码中Dog的赋值注释去掉
//Dog crabBack = (Dog) getobjectFromFile(fileName);
运行结果抛出错误:
Exception in thread "main" java.lang.classCastException: serializable.Person cannot be cast to serializable.Dog
说明serializable在不同类一间并不矛盾。
到此这篇关于Java SerialVersionUID作用详解的文章就介绍到这了,更多相关Java SerialVersionUID内容请搜索小编以前的文章或继续浏览下面的相关文章希望大家以后多多支持小编!
今天关于使Java运行时忽略serialVersionUID?和java忽略警告的介绍到此结束,谢谢您的阅读,有关Java private static final long serialVersionUID 作用、java serialVersionUID作用、Java serialVersionUID作用和生成、Java SerialVersionUID作用详解等更多相关知识的信息可以在本站进行查询。
本文标签: