首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >序列化SerialVersionUID源码及过程详解

序列化SerialVersionUID源码及过程详解

原创
作者头像
Mr.Shelby
发布2025-07-02 21:24:17
发布2025-07-02 21:24:17
690
举报

序列化SerialVersionUID源码及过程详解——Java

当某一天我正常的周六加班又没啥事干的时候,莫名的来了一个无法序列化的错误(很快啊,就引起了我的注意)这就引入了接下来的主角——serialVersionUID。关于它的用途介绍已经很详细了,这里不解释,直接上源码。

这是一段非常简单的序列化代码,通过输入输出流来将对象生成解析成二进制数据
代码语言:java
复制
public class SerializeDemo {
    public static void serialize(Person person,String fileName) throws IOException {
        new ObjectOutputStream(new FileOutputStream(fileName)).writeObject(person);
    }
    public static Person deSerialize(String fileName) throws IOException,ClassNotFoundException{
       return (Person) new ObjectInputStream(new FileInputStream(fileName)).readObject();
    }

    public static void main(String[] args) throws IOException,ClassNotFoundException {
        serialize(new Person("LordYi",22),"myText.byte");
        System.out.println(deSerialize("myText.byte"));
    }
}
代码语言:java
复制
public class Person implements Serializable {
   private static final long serialVersionUID=2L;//重点来了哦
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
当我们指定了UID时,jvm会获取到。并且在这之后如果我们修改了Person类,例如加了个方法,属性。在序列化时就不会报错。反之,它就给你爆红了啦啦啦啦啦。tips(当初我一不小心将long写成了Long,导致一直结果不符合预期结果,快给我整抑郁以为科学不存来了才发现这个,加深印象,它就是一串数字😂😂😂)
再serialize后会生成myText.Byte文件,后缀啥的都不重要。不要像我一开时那样犯傻,运行代码的时候不要同时即serialize又deSerialize。如果你想测试代码,验证改了Person类结构后是否会解析失败,就不要运行serialize啦,注释掉它直接deserialize就好了,不然你永远是对滴。😁
上图
在这里引入一个关键类ObjectStreamClass,序列化的大部分工作都在此类完成。
从writeObject方法进入writeObject0可以看到
代码语言:java
复制
static ObjectStreamClass lookup(Class<?> cl, boolean all) {
        if (!(all || Serializable.class.isAssignableFrom(cl))) {
            return null;
        }
        return Caches.localDescs.get(cl);
    }
在通过ClassCache这个静态内部类时会进行ObjectStreamClass的初始化,通过反射去拿到这个类的信息
代码语言:java
复制
private static class Caches {
        /** cache mapping local classes -> descriptors */
        static final ClassCache<ObjectStreamClass> localDescs =
            new ClassCache<>() {
                @Override
                protected ObjectStreamClass computeValue(Class<?> type) {
                    return new ObjectStreamClass(type);
                }
            };
    }
下面就很简单啦,有就直接返回,木有就自己compute一下。简单介绍下compute就是将这个类的类名,字段,方法等一些信息集中计算成一个Hash值。
代码语言:java
复制
public long getSerialVersionUID() {
        // REMIND: synchronize instead of relying on volatile?
        if (suid == null) {
            if (isRecord)
                return 0L;

            suid = AccessController.doPrivileged(
                new PrivilegedAction<Long>() {
                    public Long run() {
                        return computeDefaultSUID(cl);
                    }
                }
            );
        }
        return suid.longValue();
    }

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 序列化SerialVersionUID源码及过程详解——Java
    • 当某一天我正常的周六加班又没啥事干的时候,莫名的来了一个无法序列化的错误(很快啊,就引起了我的注意)这就引入了接下来的主角——serialVersionUID。关于它的用途介绍已经很详细了,这里不解释,直接上源码。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档