序列化版本号serialVersionUID的作用_动力节点Java学院整理

序列化是Java中非常重要且常用的一个功能。它在实现网络通信、分布式存储等方面都有广泛的应用。而序列化版本号serialVersionUID则是保证序列化的兼容性和稳定性的重要手段,它用于判断序列化对象的版本是否一致,如果不一致则不能反序列化。

在Java中,每个class都有一个serialVersionUID属性,它是一个长整型数字。如果不显式指定,Java会自动生成一个serialVersionUID。当对象被序列化时,Java会将序列化对象的对象流中写入serialVersionUID,并且在反序列化时校验该数字。

serialVersionUID的作用就是当序列化一个对象时,Java会判断这个对象的serialVersionUID和本地JVM中对应的serialVersionUID是否一致。如果一致,则可以反序列化这个对象;如果不一致,则会抛出InvalidClassException异常,反序列化失败。

示例一:同一版本的序列化和反序列化

import java.io.*;

public class SerializationTest {

    private static final String FILE_PATH = "user.ser";

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        User user = new User("张三", 20);
        System.out.println("序列化前: " + user);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH));
        oos.writeObject(user);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH));
        User newUser = (User)ois.readObject();
        ois.close();
        System.out.println("序列化后: " + newUser);
    }

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

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

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}

执行结果如下:

序列化前: User{name='张三', age=20}
序列化后: User{name='张三', age=20}

示例二:不同版本的序列化和反序列化

import java.io.*;

public class SerializationTest {

    private static final String FILE_PATH = "user.ser";

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        User user = new User("张三", 20);
        System.out.println("序列化前: " + user);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH));
        oos.writeObject(user);
        oos.close();
        // 修改User对象的属性age的类型为long
        File file = new File(FILE_PATH);
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        byte[] bytes = new byte[(int)randomAccessFile.length()];
        randomAccessFile.readFully(bytes);
        bytes[43] = 0x4C; // 修改0x10为0x4C
        randomAccessFile.seek(0);
        randomAccessFile.write(bytes);
        randomAccessFile.close();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH));
        User newUser = (User)ois.readObject();
        ois.close();
        System.out.println("序列化后: " + newUser);
    }

    private static class User implements Serializable {
        private static final long serialVersionUID = 1L;
        private String name;
        private long age;

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

        // 省略 toString 方法
    }
}

执行结果如下:

序列化前: User{name='张三', age=20}
Exception in thread "main" java.io.InvalidClassException: SerializationTest$User; local class incompatible: stream classdesc serialVersionUID = 7528517758001900623, local class serialVersionUID = 1

可以看到,当User对象被成功序列化后,我们故意修改了其属性age的类型,并重新读取了文件进行反序列化,我们得到了一个InvalidClassException异常的提示,反序列化失败。

在以上两个示例中,我们可以看到serialVersionUID属性的作用。当我们使用序列化功能时,一定要注意并理解这个字段的含义,以防止在使用中产生意外的错误。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:序列化版本号serialVersionUID的作用_动力节点Java学院整理 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • springmvc利用jquery.form插件异步上传文件示例

    针对你的问题,我可以提供以下完整攻略,希望能够帮助你。 一、简介 在web应用中,文件上传功能是比较常见的。而在Spring MVC框架中,文件上传则可以通过SpringMVC提供的MultipartHttpServletRequest类来完成,但是这种方式需要整个页面提交才能上传文件,速度比较慢,因此在前端使用异步上传文件功能可以大幅提升用户体验。而jqu…

    Java 2023年5月31日
    00
  • Java使用动态规划算法思想解决背包问题

    Java 使用动态规划算法思想解决背包问题 什么是动态规划算法 动态规划(Dynamic Programming)是一种解决多阶段决策问题的优化方法。它将问题分解为多个阶段,并针对每个阶段进行决策。每个阶段的决策将会影响后续的阶段,因此需要对每个阶段进行全局最优化的考虑,以确保最终的结果是最优的。 背包问题 背包问题(Knapsack Problem)是常见…

    Java 2023年5月19日
    00
  • 深入了解Java定时器中的Timer的原理

    深入了解Java定时器中的Timer的原理攻略 什么是Java定时器 在Java中,我们可以使用定时器来实现周期性和延迟任务。定时器可以根据开发人员设定的时间间隔周期性地触发任务,并且可以延迟执行某个任务。其中,Java Timer则是Java提供的一个定时器工具,能够实现任务的定时执行。 Java Timer的工作原理 Java Timer是基于Java的…

    Java 2023年5月20日
    00
  • JSP教程(一)

    下面是“JSP教程(一)”的完整攻略: JSP教程(一) 什么是JSP JSP(Java Server Pages) 是一种动态网页开发技术,它是由Servlet API的编程模型衍生而来的。JSP技术将Java代码嵌入到HTML文档中,用于动态处理网页的内容。当客户端发起请求时,JSP容器会将JSP编译为Servlet并执行。 JSP的特点 处理动态内容 …

    Java 2023年6月15日
    00
  • Java面试题冲刺第十一天–集合框架篇(2)

    我会详细讲解Java面试题冲刺第十一天–集合框架篇(2)的完整攻略。 题目说明 本题主要涉及Java中集合框架的部分知识点,包括ArrayList、LinkedList、HashSet、LinkedHashSet、TreeSet等类的使用、特性、区别及适用场景等方面的内容。 解题思路 一、ArrayList与LinkedList的区别 1.底层数据结构不同…

    Java 2023年5月19日
    00
  • JVM的内存回收及常见算法小结

    JVM的内存回收及常见算法小结 什么是垃圾回收? 垃圾回收是指通过某些算法与过程,自动回收程序中不再被使用且占用内存的变量及对象等资源。JVM内置了垃圾回收机制,来管理Java程序使用的内存。垃圾回收可以帮助程序员有效地管理内存,减少内存泄露等问题。 JVM内存模型 JVM将内存分为三个区域:程序计数器、Java栈与Java堆。 程序计数器:记录当前线程运行…

    Java 2023年6月16日
    00
  • Java 创建线程的3种方法及各自的优点

    下面我将为您详细讲解“Java 创建线程的3种方法及各自的优点”的完整攻略。 Java 创建线程的3种方法及各自的优点 在Java中,创建线程有三种常用的方法,分别为继承Thread类、实现Runnable接口和实现Callable接口。各自的优点如下: 继承Thread类 继承Thread类创建线程是最简单的方法,只需要重写Thread类的run方法即可。…

    Java 2023年5月18日
    00
  • 如何理解Java内存模型?

    如何理解Java内存模型? Java内存模型(Java Memory Model,JMM)规定了Java程序中多线程执行时,线程之间内存的交互以及对共享数据的访问方式,它是Java程序能否正确运行的重要保障。 Java内存模型的重要概念 主内存和工作内存 Java内存模型中,有两种内存: 主内存(Main Memory):所有线程可以访问共享的内存区域,主内…

    Java 2023年5月11日
    00
合作推广
合作推广
分享本页
返回顶部