• Java序列化详解(基础入门)


    【辰兮要努力】:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行!

    博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端、后台、数据库、项目案例等相关知识点总结,感谢你的阅读和关注,希望我的博客能帮助到更多的人,分享获取新知,大家一起进步!

    吾等采石之人,应怀大教堂之心,愿我们奔赴在各自的热爱里…

    一、概念入门

    程序在运行时实例化出对象,这些对象存在于内存中,随着程序运行停止而消失,但如果我们想把某些对象(一般都是各不相同的属性)保存下来或者传输给其他进程,在程序终止运行后这些对象仍然存在,可以在程序再次运行时读取这些对象的信息,或者在其他程序中利用这些保存下来的对象信息恢复成实例对象。这种情况下就要用到对象的序列化和反序列化。

    总结:如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,这些场景都需要用到序列化。

    • 序列化: 将数据结构或对象转换成二进制字节流的过程
    • 反序列化:将在序列化过程中所生成的二进制字节流的过程转换成数据结构或者对象的过程
      在这里插入图片描述

    序列化主要有两个用途

    • 把对象的字节序列永久保存到硬盘上,通常存放在一个文件中(序列化对象)
    • 在网络上传送对象的字节序列(网络传输对象)

    二、基础进阶

    什么情况下需要序列化?

    当我们需要将对象的状态信息通过网络进行传输,或者需要将对象的状态信息持久化,以便将来使用时都需要把对象进行序列化。

    Java如何实现序列化?

    实现Serializable接口

    package java.io;
    
    public interface Serializable {
    }
    
    • 1
    • 2
    • 3
    • 4

    Java序列化为什么要实现Serializable接口?

    Serializable只是标识类对象为Serializable,真正工作的是ObjectO/FileInputStream中的WriteObject()与readObject()函

        // remaining cases
           if (obj instanceof String) {
               writeString((String) obj, unshared);
           } else if (cl.isArray()) {
               writeArray(obj, desc, unshared);
           } else if (obj instanceof Enum) {
               writeEnum((Enum<?>) obj, desc, unshared);
           } else if (obj instanceof Serializable) {
               writeOrdinaryObject(obj, desc, unshared);
           } else {
               if (extendedDebugInfo) {
                   throw new NotSerializableException(
                       cl.getName() + "\n" + debugInfoStack.toString());
               } else {
                   throw new NotSerializableException(cl.getName());
               }
           }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    从上源码分析,如果被写对象的类型是String,或数组,或Enum,或Serializable,那么就可以对该对象进行序列化,否则将抛出NotSerializableException。


    案例:定义一个类实现Serializable 接口

    在这里插入图片描述

    序列化版本号serialVersionUID相关讲解

    我们知道,反序列化必须拥有class文件,但随着项目的升级,class文件也会升级,序列化怎么保证升级前后的兼容性呢?

    public class Student implements Serializable {
        //序列化版本号
        private static final long serialVersionUID = 100013L;
        private String name;
        private int age;
        //set,get方法及构造方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Java序列化提供了一个private static final long serialVersionUID 的序列化版本号,只有版本号相同,即使更改了序列化属性,对象也可以正确被反序列化回来。

    如果反序列化使用的class的版本号与序列化时使用的不一致,反序列化会报InvalidClassException异常。

    序列化版本号可自由指定,如果不指定,JVM会根据类信息自己计算一个版本号,这样随着class的升级,就无法正确反序列化;不指定版本号另一个明显隐患是,不利于jvm间的移植,可能class文件没有更改,但不同jvm可能计算的规则不一样,这样也会导致无法反序列化。

    强烈推荐每个序列化类都手动指定其 serialVersionUID,如果不手动指定,那么编译器会动态生成默认的序列化号


    三、应用场景

    常见的关于序列化和反序列化的案例?

    • 将对象存储到文件中的时候需要进行序列化,将对象从文件中读取出来需要进行反序列化。
    • 当你想在网络传输中传送 Java 对象时,可以使用序列化。(比如远程方法调用 RPC 的时候)之前需要先被序列化,接收到序列化的对象之后需要再进行反序列化;
    • 将对象存储到缓存数据库(如 Redis)时需要用到序列化,将对象从缓存数据库中读取出来需要反序列化。

    为什么 RPC 调用需要序列化?

    因为网络传输的数据必须是二进制数据,所以在 RPC 调用中,对入参对象与返回值对象进行序列化与反序列化是一个必须的过程。


    📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤️ 分享👥 留言💬thanks!!!

    📚愿我们奔赴在各自的热爱里!

  • 相关阅读:
    Redis Cluster 数据分片
    大写字母转小写字母
    DS Transunet:用于医学图像分割的双Swin-Transformer U-Net
    Nginx的常用命令和配置文件
    内存取证入门第二题
    不清楚的照片如何变清晰?教你几招变清晰的方法
    原码反码补码疑惑解答记录:127+1=-128
    python使用Postgre数据库使用geometry和批量插入数据以及python库psycopg2操作postgre数据库踩坑
    自动化安装脚本(Ansible+shell)
    django基于python的疫情防控下医院人员调动系统--python-计算机毕业设计
  • 原文地址:https://blog.csdn.net/weixin_45393094/article/details/126192236