必威体育Betway必威体育官网
当前位置:首页 > IT技术

Java对象序列化为什么要使用SerialversionUID

时间:2019-10-09 23:14:26来源:IT技术作者:seo实验室小编阅读:74次「手机版」
 

serialversionuid

1、首先谈谈为什么要序列化对象

     - 把对象转换为字节序列的过程称为对象的序列化。
     - 把字节序列恢复为对象的过程称为对象的反序列化。

对象的序列化主要有两种用途:

1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;

2) 在网络上传送对象的字节序列。

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象

2、为什么要使用serialversionuid

简单看一下 serializable接口的说明

  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. 

如果用户没有自己声明一个serialVersionUID,接口会默认生成一个serialVersionUID

However, it is stronglyrecommended that all serializable classes explicitly declareserialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpectedInvalidClassExceptions during deserialization.

但是强烈建议用户自定义一个serialVersionUID,因为默认的serialVersinUID对于class的细节非常敏感,反序列化时可能会导致InvalidClassException这个异常。

e.g:1.使用默认的serialVersionUID

我们先建一个实体类Person 实现Serializable接口

public class Person implements Serializable {
    

    private int age;
    private String name;
    private String sex;
  

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

然后去序列化和反序列化它

public class TestPersonserialize {

    public static void main(String[] args) throws Exception {
        serializePerson();
        Person p = deserializePerson();
        System.out.println(p.getName()+";"+p.getAge());
        
        
    }
    
    private static void serializePerson() throws filenotfoundException,IOException {
        Person person = new Person();
        person.setName("测试实例");
        person.setAge(25);
        person.setSex("male");

        Objectoutputstream oo = new ObjectOutputStream(new FileOutputStream(
                new File("E:/person.txt")));
        oo.writeObject(person);
        System.out.println("序列化成功");
        oo.close();
    }
    
    private static Person deserializePerson() throws IOException, Exception {
        ObjectInputStream ois = new ObjectInputStream(new fileinputstream(new File("E:/person.txt")));
        Person person = (Person) ois.readObject();
        System.out.println("反序列化成功");
        return person;
    }
}

结果如图

这里写图片描述

e.g:2

如果我们先尽心序列化,然后在反序列化之前修改了Person类会怎样呢

public class Person implements Serializable {
    
    private int age;
    private String name;
    private String sex;
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

运行结果

这里写图到底片描述

可以看到,当我们修改Person类的时候,Person类对应的SerialversionUID也变化了,而序列化和反序列化就是通过对比其SerialversionUID来进行的,一旦SerialversionUID不匹配,反序列化就无法成功。在实际的生产环境中,我们可能会建一系列的中间Object来反序列化我们的pojo,为了解决这个问题,我们就需要在实体类中自定义SerialversionUID。

e.g:3 在Person类中加入自定义SerialversionUID

public class Person implements Serializable {
    
   private static final long serialVersionUID = -5809782578272943999L;
    private int age;
    private String name;
    private String sex;
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

不管我们序列化之后如何更改我们的Person(不删除原有字段),最终都可以反序列化成功。

相关阅读

2018年支持java8的Java反编译工具汇总

大多商业软件,会对程序进行加密、加壳等安全措施以防范软件被破解,从而使得反编译越来越难。反编译是一个对目标可执行程序进行逆向

javascript中void(0);用法及常见问题解析

转载这篇文章 使用过ajax的朋友经常会见到这样的代码:here,这里面的void是一个操作符,该操作符指定要计算一个表达式但是不返回值。j

【java.lang.reflect】反射机制应用及详解

最近也是面试的时候问道一个问题,如何将一个java对象转换为json字符串,一听到的时候没有任何思路,之前也有接触过fastjson,知道就是用

婚礼纪 java面试

我现在只是一个快2年经验的平凡的菜鸡boy 第一面架构师面试 1、简单介绍一下你经常使用的集合 2、什么是线程安全 3、arraylist和

Java实现MD5加密的方式

MD5加密是一种常见的加密方式,我们经常用在保存用户密码和关键信息上。那么它到底有什么,又什么好处呢,会被这么广泛的运用在应用开

分享到:

栏目导航

推荐阅读

热门阅读