前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SHA指纹算法进行版本管理,解决对象流序列化与反序列化不兼容的问题

SHA指纹算法进行版本管理,解决对象流序列化与反序列化不兼容的问题

作者头像
Java深度编程
发布2020-06-17 14:35:21
7980
发布2020-06-17 14:35:21
举报
文章被收录于专栏:Java深度编程Java深度编程

首先,我们先说一下什么是对象流的序列化与反序列化。我们知道代码创建的对象起初是存在计算机内存中的,将内存中的数据存入磁盘则是“序列化”;将磁盘中的文件数据重新加载到内存,称为“返序列化”;将内存中的数据先封装成对象,再将对象与流的形式进行与硬件磁盘,内存的交互行为,则称之为“对象流的序列化与反序列化”。

java针对对象流的序列化与反序列化提供了专门的类来处理,这个类是:ObjectInputStream(输入流)和ObjectOutputStream(输出流)

废物我们不多说,直接上代码:

package com.wenxue.io;

import java.io.*;

/**
 * @className: ObjectStreamSerialTest
 * @Description: TODO 对象流的序列化与反序列化
 * @version: v1.8.0
 * @author: GONGWENXUE 《微信公众号:Java深度编程》
 * @date: 2020/6/13 16:28
 */
public class ObjectStreamSerialTest {


    public static void main(String[] args) {
        wirterObject();
        readObject();
    }

    /**
     * @Author GONGWENXUE
     * @Description //TODO 写出对象,序列号对象
     * @version: v1.8.0
     * @Date 16:37 2020/6/13
     * @Param
     * @return
     **/
    public static void wirterObject() {
        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("C:\\user.bat"));
            User user = new User(17, "文学");
            out.writeObject(user);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @Author GONGWENXUE
     * @Description //TODO 读对象,反序列号对象
     * @version: v1.8.0
     * @Date 16:37 2020/6/13
     * @Param
     * @return
     **/
    public static void readObject() {
        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("C:\\user.bat"));
            User user = (User)in.readObject();
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    static class User implements Serializable{
        int age;
        String name;

        public User(int age, String name) {
            this.age = age;
            this.name = name;
        }
    }
}

当运行wirterObject()方法时,会在C盘下生产一个文件,如下:

使用Notepad++打开此user.bat文件,显示内容如下:

¬í sr )com.wenxue.io.ObjectStreamSerialTest$User¹0ì]|J|Õ I ageL namet Ljava/lang/String;xp   t 文学

当调用readObject()时,可以重新将序列化的user对象再次的°读回内存,但这并不一定会成功,这是为什么呢?

试想一下,我们有这么一个应用场景,在反序列化的时候User类对象可能已经经过了多次的修改,版本已经升级过多次了,可能已经和当初序列化时的数据结构,类型,方法等均不一致了,从而导致无法正常进行反序列化。要解决这个问题就需要使用到java的版本管理机制。

java为了解决此类问题,特意推出了SerialVersionUID来解决这个问题。该值常出现在类的成员变量中,鲜少有人注意,大部人也不知道是用来干嘛用的。

public class ObjectStreamSerialTest {
    public static final long serialVersionUID = -34933310492167L;
    //……
}

这个值是怎么来的,首先我们需要了解下对象序列化的文件格式,及SHA算法。

下对象序列化的文件格式

对象序列化是以特殊的文件格式存储对象的,当存储一个对象的时候也必须要存储这个类,其中包含了:

  1. 类名;
  2. 序列化的唯一版本ID,它是数据域类型和方法签名的指纹;
  3. 面熟序列化方法的标准集;
  4. 对数据域的描述。

指纹是通过对类,超类,接口,域类型和方法签名按照规范方法排序,然后将安全散列算法(SHA)应用与这个数据而获得的。

SHA是一种可以为较大信息会提供指纹的快速算法,这种指纹总是20个字节的数据包。java对象的序列化机制采取了SHA码的前8个字节作为类的指纹。在读入一个对象的时候,会拿着指纹与当前类的指纹比对,如果不匹配,说明这个类已经产生了变化,因此反序列化时会产生异常。而使用SerialVersionUID后就指定了类的指纹一定就是这个了,所以反序列化的时候能够匹配上,但这也不代表就一定能反序列化成功,这又是为何呢?

当类被修改以后,假如只是修改了方法是不会影响反序列化的,但如果是变量就不一定了。我们假设有这么一个场景,User类在修改前有一个属性,int a = 1; 修改后User类的属性变成了String a;那么这时候java的反序列化机制会自动匹配类型,匹配不成功就会自动转换其类型(将int装成String,得到String a = "1"),此种情况自然能够转换成功。但假如User类修改前是String s = “abc”, 修改后是 int a; 那么怎么可能将字符串“abc”转成int类型呢,所以一定会失败。所以使用SerialVersionUID也未必能保证序列化后一定能反序列化成功。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java深度编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档