4.4 序列化与反序列化

news2024/11/25 18:32:43

文章目录

  • 1.概述
  • 2.特点/应用场景
  • 3.涉及到的流对象
  • 4.代码实现序列化与反序列化
    • 4.1 步骤1:创建学生类Student2
    • 4.2 步骤2:创建序列化测试类
  • 5.测试案例中常见的几种编译错误类型
  • 6.为什么反序列化版本号需要与序列化版本号一致?
  • 7.自动提示 生成UID 链接的设置


1.概述

  1. 序列化 ObjectOutputStream

    • 是指把程序中的java对象,通过序列化流oos输出到磁盘的文件中,相当于数据写出的过程,利用ObjectOutputStream,把对象的信息,按照固定的格式转成一串字节值输出并持久保存到磁盘
    • 方向是OUT,使用的流是ObjectOutputStream
    • 使用的方法是out.writeObject(目标对象);
    • 注意:如果一个类的对象想要被序列化,那么这个类必须实现Serializable接口
  2. 反序列化 ObjectInputStream

    • 是指把之前已经保存在文件中的对象的相关数据,通过反序列化流ois读到内存中的过程中,并把读到的数据恢复成对象,利用ObjectInputStream,读取磁盘中之前序列化好的数据,重新恢复成对象
    • 相当于数据读取的过程,方向是in,使用的流是ObjectInputStream
    • 使用的方法是in.readObject();
    • 注意:反序列化指定的文件路径,必须与序列化输出的文件路径一致
    • 注意:一次序列化操作对应一次反序列化操作,或者UID必须保持一致,如果不一致,会报错

在这里插入图片描述

2.特点/应用场景

  1. 需要序列化的文件必须实现Serializable接口,用来启用序列化功能
  2. 不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出
  3. 每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个
  4. 在反序列化时,如果和序列化的版本号不一致,无法完成反序列化
  5. 常用与服务器之间的数据传输,序列化成文件,反序列化读取数据
  6. 常用使用套接字流在主机之间传递对象
  7. 不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存

3.涉及到的流对象

序列化:Object OutputStream
ObjectOutputStream 将 Java 对象的基本数据类型写入 OutputStream,通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

构造方法:
ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream
普通方法:
writeObject(Object obj)
将指定的对象写入 ObjectOutputStream

反序列化:ObjectInputStream
ObjectInputStream对以前使用ObjectOutputStream写入的基本数据和对象进行反序列化重构对象。

构造方法:
ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream
普通方法:
readObject() 从 ObjectInputStream 读取对象

4.代码实现序列化与反序列化

4.1 步骤1:创建学生类Student2

package partThree;
/*本类用于序列化测试的物科类*/
public class Student2 {
    //定义学生相关的属性并进行封装
    private String name; //姓名
    private int age; //年龄
    private String addr; //地址
    private char gender;//性别

    //2.1 创建本类的无参构造--注意必须手动提供无参构造,否则会被覆盖
    public Student2() {
        System.out.println("我是Student的无参构造");
    }

    //2.2创建全参构造
    public Student2(String name, int age, String addr, char gender) {
        super();//默认调用父类的无参构造
        this.name = name;
        this.age = age;
        this.addr = addr;
        this.gender = gender;
        System.out.println("我是Student的全参构造");
    }

    //3.属性封装后,需要本类提供公共的属性访问与设置方式get()&set()

    /**
     * 自动创建get()&set(),右键-->Source-->Generate Getters and Setters...
     */
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
    //如果不想查看对象的地址值,而是想查看类型 属性 属性值
    //可以在子类中添加重写的toString()


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

4.2 步骤2:创建序列化测试类

package partThree;

import java.io.*;

/* 本类用于测试对象的序列化与反序列化
 *  序列化 ObjectOutputStream
 *  是指把程序中的java对象,通过序列化流oos输出到磁盘的文件中,相当于数据写出的过程
 * 反序列化  ObjectInputStream
 * 是指把之前已经保存在文件中的对象的相关数据,通过反序列化流ois读到内存中的过程中
 * 相当于数据读取的过程*/
public class TestSerializable {
    public static void main(String[] args) {
        method1(); //本方法用来完成序列化的功能
        method2(); //本方法用于完成反序列化功能
    }

    private static void method2() {
        //1.定义一个在本方法中都生效的局部变量,注意初始化
        ObjectInputStream in = null;
        //2.由于IO操作可能会产生异常,所以完成try-catch-finally结构
        try{
            //3.创建反序列化流ois
            in = new ObjectInputStream(new FileInputStream("E:\\ready\\1.txt"));
            //4.通过反序列化流,读取文件中的数据,并把读到的数据,回复成数据
            Object o = in.readObject();
            System.out.println(o); //将接到的对象打印
            System.out.println("恭喜您,反序列化成功!");
        }catch(Exception e){
            System.out.println("很抱歉,反序列化失败!");
            e.printStackTrace();
        }finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    private static void method1() {
        //定义一个在本方法中都生效的局部变量,注意初始化
        ObjectOutputStream out = null;
        try {
            //1.创建流对象--需要try-catch,需要设置FileOutputStream子类,
            // 并设置传输文件路径表明要把序列化后的对象数据输出到哪个文件中
            out = new ObjectOutputStream(new FileOutputStream("E:\\ready\\1.txt"));
            //2.使用流对象
            //2.1 指定一个要序列化输出的对象,并设置属性
            Student2 s = new Student2("海绵宝宝",3,"海里",'男');
            //2.2 序列化输出对象s到文件中
            out.writeObject(s);
            System.out.println("恭喜您,序列化成功!");
            //成功后,我们可以在目标文件里看到序列化输出的数据,但注意,这个数据是为了底层保存对象和传输使用的,我们看不懂
            //有些类似于我们字节码文件中的数据
        } catch (IOException e) {
            System.out.println("很抱歉,序列化失败!");
            e.printStackTrace();
        }finally {
            //3.关闭流对象
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

5.测试案例中常见的几种编译错误类型

在这里插入图片描述

NotSerializableException:报错原因:要序列化对象所在的类并没有实现序列化接口
解决方案:实现序列化接口

在这里插入图片描述

InvalidClassException:报错原因:更改子类数据后,会导致本次反序列化时使用的UID与序列化时的UID不匹配
解决方案:反序列化时的UID与序列化时的UID要保持一致,或者测试时一次序列操作对应一次反序列化操作,否则不匹配就报错,重新进行一次序列化后,再进行反序列化即可;

6.为什么反序列化版本号需要与序列化版本号一致?

我们在反序列化时,JVM会拿着反序列化流中的serialVersionUID与序列化时相应的实体类中的serialVersionUID来比较,如果不一致,就无法正常反序列化,出现序列化版本不一致的异常InvalidClassException。

而且我们在定义需要序列化的实体类时,如果没有手动添加UID,
Java序列化机制会根据编译的class自动生成一个,那么只有同一次编译生成的class才是一样的UID。

如果我们手动添加了UID,只要这个值不修改,就可以不论编译次数,进行序列化和反序列化操作。

7.自动提示 生成UID 链接的设置

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/336601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

10 亿月活用户下,快手基于 Dragonfly 的超大规模镜像分发实践

背景 挑战 快手容器云平台旨在为快手不断增长、不断变化和多样化的业务,提供基于容器化部署的超大规模基础设施服务。为了实现这一目标,快手工程师需要解决弹性、稳定性、效率和无服务器架构等挑战,在这些挑战中,镜像分发的稳定…

职场IT老手教你3步教你玩转可视化大屏设计,让领导眼前一亮!

我是制造企业的IT中心的研发人员,平常工作就是配合业务部门出出报表,选型一些商业软件,并在内部负责实施运维。最近领导出去参观了一些数字化转型比较领先的工厂和制造企业,回来就甩给我几张图,问能不能我们也做几个这…

4. sql 语句中常用命令

1. 数据表: 本文中所有命令,测试的数据表结构如下图: 2. 查询语句: 2.1 基础查询:select //查询单个字段: select 字段名 from 表名; //查询多个字段 select 字段名1,字段名2,... from 表名; //查询所…

数据库的安装部署

目录 方法一:仓库安装 一、添加MySQL仓库 二、安装装MySQL 三、启动MySQL服务器 方法二:本地安装 一、使用以下执行清理之前实验MySQL仓库安装的数据库: 二、网上下载mysql的安装包 三、将下载好的文件传入Redhat中的某个路径中 …

CentOS7安装配置OpenVNP连接远端服务器

在项目当中需要访问一个三方接口及数据库,但是需要在CentOS7服务器上先配置OpenVPN,然后才能连接,现将整体配置过程记录如下。 安装 yum -y install epel-release yum -y install openvpn 查看版本 openvpn --version 配置客户端证书 打开…

电脑ip地址查询要怎么做?查询IP地址就看这3种方法

电脑无法运转时,我们需要别人的帮忙的话,那就需要知道自己电脑的IP地址是什么。但是很多人不知道该从电脑哪里找到IP地址。电脑ip地址查询就看下面2种方法,让你轻松就能Get到技巧! 操作环境: 演示机型:华为…

【数据库】 数据库的理论基础详解

目录 一, 什么是数据库 二, 数据库管理系统(DBMS) 三,数据库与文件系统的区别 1,对比区别: 2,优缺点总结: 四,数据库的发展史 五,常见数据库 1, 关系型…

vue directive 注册局部指令

注册局部指令 vue directive 在注册局部指令时,是通过在组件 options 选项中设置 directives 属性。如下: directives: {focus: {// 指令的定义inserted: function (el) {el.focus()}} }在模板中的任何元素上都可以使用新的 v-focus property&#xff…

前端登录状态验证Session和Token的区别

(1)Session客户端发送一个登录请求,服务器验证登录数据无误,会生成一个sessionID,此ID对应的值即登录状态为已登录。服务器有一个key-value映射表,会把这个ID和登录状态存到此表中。服务器返回的响应头的se…

好用的iPhone 数据恢复软件精选

随着 Apple 的 iTunes / iCloud 备份服务的兴起,我们总是假设这些信息在我们需要的时候可以随时访问。然而,事实是,意想不到的“不幸”发生了,比如 iOS 升级失败、忘记密码,或者更严重的情况,如进水或被盗。…

Ansible的脚本------playbook剧本

一、剧本的前置知识点1、主机清单ansible默认的主机清单是/etc/ansible/hosts文件主机清单可以手动设置,也可以通过Dynamic Inventory动态生成一般主机名使用FQDNvi /etc/ansible/hosts [webserver] #使用方括号设置组名 www1.example.org #定…

想要精通算法和SQL的成长之路 - 接雨水

想要精通算法和SQL的成长之路 - 接雨水前言一. 接雨水前言 想要精通算法和SQL的成长之路 - 系列导航 一. 接雨水 原题链接 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 输入:height [0,…

【RabbitMQ】注册成功后的通知操作

目录前提说明代码实现1. 依赖2. 配置类3. 生产方创建测试类,目的:查看是否队列交换机创建成功,且在队列里面是否有一条待消费的信息。4. 消费方最后前提说明 背景条件:主要是自己学完了RabbitMQ后,想自己多去动手实践…

基于SSM的教务管理系统设计与实现

技术:Java、JSP等摘要:伴随着数字化、网络化、信息化发展的社会,越来越多的行业与时俱进融入到了互联网中,而高校作为为了一个更是培养各色人才之地,更是拥有大量的高科技人才,因此也更应该运用科技来完善教…

单片机开发---ESP32S3移植NES模拟器(二)

书接上文 《单片机开发—ESP32-S3模块上手》 《单片机开发—ESP32S3移植lvgl触摸屏》 《单片机开发—ESP32S3移植NES模拟器(一)》 暖场视频,小时候称这个为—超级曲线射门!!!!!&am…

Linux 安装jenkins和jdk11

Linux 安装jenkins和jdk111. Install Jdk112. Jenkins Install2.1 Install Jenkins2.2 Start2.3 Error3.Awakening1.1 Big Data -- Postgres4. Awakening1. Install Jdk11 安装jdk11 sudo yum install fontconfig java-11-openjdk 2. Jenkins Install 2.1 Install Jenkins 下…

八、Linux文件 - 文件IO与标准IO的区别

目录 1.Linux标准文件描述符 2.缓存的概念 1.Linux标准文件描述符 文件描述符缩写描述0STDIO标准输入1STDOUT标准输出2STDERR标准错误输出文件IO:是直接调用内核提供的系统调用函数,头文件时unistd.h标准IO:是间接调用系统调用函数&#x…

C语言经典编程题100例(21-40)

21、练习3-2 计算符号函数的值对于任一整数n,符号函数sign(n)的定义如下:请编写程序计算该函数对任一输入整数的值。输入格式:输入在一行中给出整数n。输出格式:在一行中按照格式“sign(n) 函数值”输出该整数n对应的函数值。输入样例1:10输出样例1:sig…

LeetCode刷题系列 -- 54. 螺旋矩阵

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。示例 1:输入:matrix [[1,2,3],[4,5,6],[7,8,9]]输出:[1,2,3,6,9,8,7,4,5]示例 2:输入:matrix [[1,2,3,4],[…

Nextcloud通过不被信任的域名访问解决方法 Nextcloud 您正在访问来自不信任域名的服务器

windows电脑在网页端输入“http://192.168.xxx.xxx:8080/login”访问远程ubuntu18.04服务器,访问其docker镜像的Nextcloud,提示“”Nextcloud通过不被信任的域名访问解决方法 Nextcloud 您正在访问来自不信任域名的服务器“”,如下图&#xf…