`
x10232
  • 浏览: 55405 次
  • 来自: 北京
社区版块
存档分类
最新评论

Serializable serialVersionUID

    博客分类:
  • Java
阅读更多
serialVersionUID适用于Java的序列化机制。简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。

serialVersionUID有两种显示的生成方式:        
一是默认的1L,比如:private static final long serialVersionUID = 1L;        
二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:        
private static final  long   serialVersionUID = xxxxL;

当一个类实现了Serializable接口,如果没有显示的定义serialVersionUID,Eclipse会提供相应的提醒。面对这种情况,我们只需要在Eclipse中点击类中warning图标一下,Eclipse就会      自动给定两种生成的方式。如果不想定义,在Eclipse的设置中也可以把它关掉的,设置如下:
Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems
将Serializable class without serialVersionUID的warning改成ignore即可。

当实现java.io.Serializable接口的类没有显式地定义一个serialVersionUID变量时候,Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果Class文件(类名,变量名,方法明等)没有发生变化(修改或增减),就算再编译多次,serialVersionUID也不会变化的。有待证明
如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。

下面用代码说明一下serialVersionUID在应用中常见的几种情况。

(1)序列化实体类
import java.io.Serializable;
public class Person implements Serializable
{
    private static final long serialVersionUID = 1234567890L;
    public int id;
    public String name;
 
    public Person(int id, String name)
    {
        this.id = id;
        this.name = name;
    }
 
    public String toString()
    {
        return "Person: " + id + " " + name;
    }
}

(2)序列化功能:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
 
public class SerialTest
{
 
    public static void main(String[] args) throws IOException
    {
        Person person = new Person(1234, "wang");
        System.out.println("Person Serial" + person);
        FileOutputStream fos = new FileOutputStream("Person.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(person);
        oos.flush();
        oos.close();
    }
}

(3)反序列化功能:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeserialTest
{
    public static void main(String[] args) throws IOException, ClassNotFoundException
    {
        Person person;
 
        FileInputStream fis = new FileInputStream("Person.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        person = (Person) ois.readObject();
        ois.close();
        System.out.println("Person Deserial" + person);
    }
 
}

情况一:假设Person类序列化之后,从A端传输到B端,然后在B端进行反序列化。在序列化Person和反序列化Person的时候,A端和B端都需要存在一个相同的类。如果两处的serialVersionUID不一致,会产生什么错误呢?
【答案】可以利用上面的代码做个试验来验证:
先执行测试类SerialTest,生成序列化文件,代表A端序列化后的文件,然后修改serialVersion值,再执行测试类DeserialTest,代表B端使用不同serialVersion的类去反序列化,结果报错:
Exception in thread "main" java.io.InvalidClassException: test.Person; local class incompatible: stream classdesc serialVersionUID = 1234567890, local class serialVersionUID = 123456789
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:560)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1580)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1493)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1729)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1326)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
    at test.DeserialTest.main(DeserialTest.java:15)
    

情况二:假设两处serialVersionUID一致,如果A端增加一个字段,然后序列化,而B端不变,然后反序列化,会是什么情况呢?
【答案】新增 public int age; 执行SerialTest,生成序列化文件,代表A端。删除 public int age,反序列化,代表B端,最后的结果为:执行序列化,反序列化正常,但是A端增加的字段丢失(被B端忽略)。

情况三:假设两处serialVersionUID一致,如果B端减少一个字段,A端不变,会是什么情况呢?
【答案】序列化,反序列化正常,B端字段少于A端,A端多的字段值丢失(被B端忽略)。

情况四:假设两处serialVersionUID一致,如果B端增加一个字段,A端不变,会是什么情况呢?
验证过程如下:
先执行SerialTest,然后在实体类Person增加一个字段age,如下所示,再执行测试类DeserialTest.
import java.io.Serializable;
public class Person implements Serializable
{
    private static final long serialVersionUID = 123456789L;
    public int id;
    public String name;
    public int age;
 
    public Person(int id, String name)
    {
        this.id = id;
        this.name = name;
    }
 
    public String toString()
    {
        return "Person: " + id + " " + name;
    }
}

相应的修改测试类DeserialTest,打印出age的值。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
 
public class SerialTest
{
 
    public static void main(String[] args) throws IOException
    {
        Person person = new Person(1234, "wang");
        System.out.println("Person Serial" + person + " age:" + person.age);
        FileOutputStream fos = new FileOutputStream("Person.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(person);
        oos.flush();
        oos.close();
    }
}

结果为:
Person Deserial Person: 1234 wang age: 0
说明序列化,反序列化正常,B端新增加的int字段被赋予了默认值0。
最后通过下面的图片,总结一下上面的几种情况。
原文链接:http://swiftlet.net/archives/1268
附:官方文档
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. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.
分享到:
评论

相关推荐

    Serializable-master.zip

    1.serialVersionUID-->适用于Java的序列化机制: 2.具体化序列化过程: 3.serialVersionUID有两种显示的生成方式:

    什么是Java的序列化和反序列化?如何实现对象的序列化和反序列化?(java面试题附答案).txt

    代码中,我们定义了一个 Person 类,...需要注意的是,序列化和反序列化的类必须具有相同的 serialVersionUID,以确保对象的一致性。同时,为了避免序列化敏感信息,可以使用 transient 关键字标记不需要序列化的字段。

    xml解析器,返回XmlNode结构,便于循环处理

    private static final long serialVersionUID = 1L; public XmlNode() { } public String tagName; public String tagValue; public String attList; public int level; public XmlNode parent; public...

    Java远程控制源代码

    private static final long serialVersionUID = 1L; private String fileName; // 文件名称 private long fileLength; // 文件长度 private byte[] fileContent; // 文件内容 public Message(){ } p

    PHP调用JAVA的WebService简单实例

    客户端提交两个String类型的参数,服务端返回一个对象类型。...public class Person implements Serializable { /** * */ private static final long serialVersionUID = -410186774891162281L; 

    java-lt:关于flink的一些测试

    java-lt 关于大数据的一些测试 idea 添加作者信息 File--> Settings--> Editor--> File and Code Templates-->...将 Serializable class without serialVersionUID 勾选 idea jihuoma #ssh 客户端 Termius

    ssh 万能类分页系统,可复用!

    import java.io.Serializable; import java.util.List; public class PageBean<DUser> implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private List<DUser> list;/...

    findbug 常见异常处理

    Class is Serializable, but doesn't define serialVersionUID 描述:类是可序列化的,但是没有定义serialVersionUID; 处理方式:自动生成serialVersionUID; Field only ever set to null 描述:Field一直被设置为...

    JAVA基础,常见java基础问题.rar

    2.接口和抽象类有什么区别 接口不能有方法实现,也就是说接口的方法都是抽象方法,但抽象类可以有方法实现。...序列化的实现一般是通过实现Serializable接口,并且会有一个serialVersionUID,这个ID叫做序列化ID

    hibernate2

    private static final long serialVersionUID = -5596241291862147220L; private int id; private String name; private int age; @Id public int getId() { return id; } public void setId(int id) { ...

    ConcurrentHashMap集合源码学习笔记

    ConcurrentHashMap继承了AbstractMap,实现了ConcurrentMap,Serializable接口,ConcurrentMap又实现了Map接口。ConcurrentHashMap是基于散列表实现的,存储的是Key/Value对,底层使用数组+链表+红黑树+CAS算法实现...

    jersey2-guicepersist-example:一个演示如何使用Guice Persist配置Jersey-2的项目

    #Jersey-2 with Guice Persist一个项目,演示如何在Jersey2(JAX-RS)容器中使用JPA配置Google Guice。 该项目不使用Guice servlet模块或Guice持久... private static final long serialVersionUID = 366534908950086

    3分钟读阿里Java手册: 序列化

    private static final long serialVersionUID = 1L; 序列化是什么 内存中的数据对象只有转换为二进制流才能进行数据持久化和网络传输。 序列化:将数据对象转换为二进制的过程称之为序列化(Serialization) 反序列化...

    Java企业微信机器人实现.pdf

    /** * 图⽂类型 */ @Data @NoArgsConstructor @AllArgsConstructor @Accessors(chain = true) public class NewArticle implements Serializable { private static final long serialVersionUID = ...

    基于Spring的HttpInvoker实现改写egova_invoker.zip

    ProxyFactory.proxy 方法,生成接口的代理对象,直接调用方法客户端和服务器端的接口和实体类要一致,实体类必须是可以序列化的比如:定义Bean: public class DemoBean implements java.io.Serializable{ ...

    memcached1

    private static final long serialVersionUID = 1945562032261336919L; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } ...

    spring_MVC源码

    16. private static final long serialVersionUID = 1L; 17. @Id 18. @Basic(optional = false) 19. @GeneratedValue(strategy = GenerationType.IDENTITY) 20. @Column(name = "id", nullable = false) 21. ...

    sesvc.exe 阿萨德

    codeceo 首页问答热门文章RSS订阅 文章首页 Java JavaScript ... iOS ...2018-07-25 分类:JAVA开发、编程开发、首页精华0人评论 来源:crossoverjie.top ...Map 这样的 Key Value 在软件开发中是非常经典的结构,常...

Global site tag (gtag.js) - Google Analytics