Java学习笔记6.3.3 文件操作 - 对象序列化与反序列化

news2024/10/6 2:21:32

文章目录

  • 零、本讲学习目标
  • 一、对象序列化与反序列化
    • (一)对象序列化与反序列化概念
    • (二)对象序列化与反序列化示意图
    • (三)实际开发中序列化和反序列化的场景
    • (四)实现对象序列化的两种方法
      • 1、实现Serializable接口
      • 2、实现Externalizable接口
    • (五)对象字节输出流
      • 1、对象字节输出流API文档
      • 2、对象字节输出流类结构图
    • (六)对象字节输入流
      • 1、对象字节输入流API文档
      • 2、对象字节输入流类结构图
  • 二、对象序列化与反序列化案例演示
    • (一)创建学生类,实现序列化接口
    • (二)创建测试学生类
      • 1、测试序列化
      • 2、测试反序列化
      • 3、serialVersionUID作用

零、本讲学习目标

  1. 了解对象序列化与反序列化应用场景
  2. 掌握如何实现对象序列化与反序列化

一、对象序列化与反序列化

(一)对象序列化与反序列化概念

  • **对象的序列化(Serialization)**是指将一个Java对象转换成一个I/O流中字节序列的过程。目的是为了将对象保存到磁盘中,或允许在网络中直接传输对象。
  • 对象序列化可以使内存中的Java对象转换成与平台无关的二进制流,既可以将这种二进制流持久地保存在磁盘上,又可以通过网络将这种二进制流传输到另一个网络节点。
  • 其他程序在获得了这种二进制流后,还可以将它恢复成原来的Java对象,将I/O流中的字节序列恢复为Java对象的过程被称之为反序列化(Deserialization)

(二)对象序列化与反序列化示意图

  • 序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中
    在这里插入图片描述

(三)实际开发中序列化和反序列化的场景

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

(四)实现对象序列化的两种方法

1、实现Serializable接口

  • 系统自动存储必要信息
  • Java内部支持,易实现,只需实现该接口即可,不需要其他代码支持
  • 性能较差
  • 容易实现,实际开发使用较多

2、实现Externalizable接口

  • 由程序员决定存储的信息
  • 接口中提供了两个空方法,实现该接口必须为两个方法提供实现
  • 性能较好
  • 编程复杂度大

(五)对象字节输出流

1、对象字节输出流API文档

  • https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/ObjectOutputStream.html
    在这里插入图片描述

2、对象字节输出流类结构图

  • ObjectOutputStream类继承了OutputStream类,实现了ObjectOutput接口和ObjectStreamConstants接口
    在这里插入图片描述

(六)对象字节输入流

1、对象字节输入流API文档

  • https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/ObjectInputStream.html
    在这里插入图片描述

2、对象字节输入流类结构图

  • ObjectInputStream类继承了InputStream类,实现了ObjectInput接口和ObjectStreamConstants接口
    在这里插入图片描述

二、对象序列化与反序列化案例演示

(一)创建学生类,实现序列化接口

  • c06.s03.p03包里创建Student类,实现Serializable接口
    在这里插入图片描述
package c06.s03.p03;

import java.io.Serializable;

/**
 * 功能:学生类,实现序列化接口
 * 作者:华卫
 * 日期:2022年12月10日
 */
public class Student implements Serializable {
    private String name;
    private int age;

    public Student() {
    }

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

    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;
    }

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

(二)创建测试学生类

  • c06.s03.p03包里创建TestStudent
    在这里插入图片描述

1、测试序列化

  • 创建testWrite()方法,测试序列化
  • 使用了单元测试包JUnit4的注解符@Test,要将JUnit4添加到类路径
    在这里插入图片描述
package c06.s03.p03;

import org.junit.Test;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

/**
 * 功能:测试学生类
 * 作者:华卫
 * 日期:2022年12月10日
 */
public class TestStudent {
    /**
     * 序列化过程
     */
    @Test
    public void testWrite() throws Exception {
        // 创建学生对象
        Student student = new Student("howard", 18);
        // 创建文件字节输出流
        FileOutputStream fos = new FileOutputStream("src/c06/s03/p03/test1.txt");
        // 创建对象字节输出流
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        // 写入学生对象数据
        oos.writeObject(student);
        // 关闭文件字节输出流
        fos.close();
        // 关闭对象字节输出流
        oos.close();
    }
}
  • 运行testWrite()方法,查看结果
    在这里插入图片描述

  • 查看生成的输出文件test1.txt
    在这里插入图片描述

  • 说明:本来写入的对象只包含两项数据:howard18,可以看到序列化后的数据明显增多了,这是Java原生序列化的一个局限性。还有一点,看到的是乱码。

  • 修改Student类,不实现Serializable接口
    在这里插入图片描述

  • 运行testWrite()方法就会抛出NotSerializableException异常
    在这里插入图片描述

  • 修改Student类,实现Serializable接口
    在这里插入图片描述

  • 序列化id: 每个对象序列化时都会生成一个序列化id,假如不手动设置,那么会自动根据当前这个类生成一个序列化id。当反序列化时,要根据序列化id来操作,如果序列化id和反序列化id不同,那么反序列化就会失败。

2、测试反序列化

  • 编写testRead()方法,测试反序列化
    在这里插入图片描述
/**                                                                                 
 * 反序列化过程                                                                           
 */                                                                                 
@Test                                                                               
public void testRead() throws Exception {                                           
    // 创建文件字节输入流                                                                    
    FileInputStream fis = new FileInputStream("src/c06/s03/p03/test1.txt");         
    // 创建对象字节输入流                                                                    
    ObjectInputStream ois = new ObjectInputStream(fis);                             
    // 读取学生对象数据                                                                     
    Student student = (Student) ois.readObject();                                   
    // 输出学生信息                                                                       
    System.out.println(student);                                                    
    // 关闭文件字节输入流                                                                    
    fis.close();                                                                    
    // 关闭对象字节输入流                                                                    
    ois.close();                                                                    
}                                                                                                                                   
  • 运行testRead()方法,查看结果
    在这里插入图片描述

  • 确实将先前序列化保存在文件中的数据读取出来,然后反序列化成Java对象输出。

3、serialVersionUID作用

  • serialVersionUID适用于Java的序列化机制。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就可以进行反序列化,否则就会出现异常。因此,为了在反序列化时确保序列化版本的兼容性,最好在每一个要序列化的类中加入private static final long serialVersionUID的变量值,具体数值可自定义(默认是1L,系统还可以根据类名、接口名、成员方法及属性等生成的一个64位的哈希字段)。这样,某个对象被序列化之后,即使它所对应的类被修改了,该对象也依然可以被正确地反序列化。
  • 修改Student类,增加一个字段gender,添加对应的getter和setter,修改toString()方法
package c06.s03.p03;

import java.io.Serializable;

/**
 * 功能:学生类,实现序列化接口
 * 作者:华卫
 * 日期:2022年12月10日
 */
public class Student implements Serializable {
    private String name;
    private int age;
    private String gender;

    public Student() {
    }

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

    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 getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}
  • 运行TestStudent类的testRead()方法,会抛出InvalidClassException异常
    在这里插入图片描述

  • 异常信息:java.io.InvalidClassException: c06.s03.p03.Student; local class incompatible: stream classdesc serialVersionUID = -6230387240686779692, local class serialVersionUID = 8464671208967089518

  • 序列化id:local class serialVersionUID = 8464671208967089518

  • 反序列化id:stream classdesc serialVersionUID = -6230387240686779692

  • 用错误提示信息中的反序列化id-6230387240686779692)去给Student类设置序列化id
    在这里插入图片描述

  • 再次运行testRead()方法,查看结果
    在这里插入图片描述

  • 修改testWrite()方法
    在这里插入图片描述

  • 运行testWrite()方法
    在这里插入图片描述

  • 运行testRead()方法,查看结果
    在这里插入图片描述

  • 查看TestStudent类源代码

package c06.s03.p03;

import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 功能:测试学生类
 * 作者:华卫
 * 日期:2022年12月10日
 */
public class TestStudent {
    /**
     * 序列化过程
     */
    @Test
    public void testWrite() throws Exception {
        // 创建学生对象
        Student student = new Student("howard", 18);
        student.setGender("男");
        // 创建文件字节输出流
        FileOutputStream fos = new FileOutputStream("src/c06/s03/p03/test1.txt");
        // 创建对象字节输出流
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        // 写入学生对象数据
        oos.writeObject(student);
        // 关闭文件字节输出流
        fos.close();
        // 关闭对象字节输出流
        oos.close();
    }

    /**
     * 反序列化过程
     */
    @Test
    public void testRead() throws Exception {
        // 创建文件字节输入流
        FileInputStream fis = new FileInputStream("src/c06/s03/p03/test1.txt");
        // 创建对象字节输入流
        ObjectInputStream ois = new ObjectInputStream(fis);
        // 读取学生对象数据
        Student student = (Student) ois.readObject();
        // 输出学生信息
        System.out.println(student);
        // 关闭文件字节输入流
        fis.close();
        // 关闭对象字节输入流
        ois.close();
    }
}

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

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

相关文章

26岁,干了三年测试,月薪才12k,能跳槽找到一个更高薪资的工作吗?

在我们的身边,存在一个普遍现象:很多人从事软件测试岗,不计其数,经历的心酸难与外人道也。可是技术确难以提升、止步不前,薪资也只能看着别人水涨船高,自己却没有什么起色。 虽然在公司里属于不可缺少的一…

计算机网络:数据链路层

数据链路层 数据链路层主要处理单个链路上如何传输数据,并且向网络层向上提供服务 1. 数据链路层概述 1.1 术语介绍 主机拥有全部的计算机网络结构,路由器只有一部分 各个路由器之间由物理层连接 红线为发送的信息 1.2 数据链路层的三个重要问题 封装…

职业危机:从无到有,从弱到强;反思再反思和应对措施

一、写在开头 每天每周不写点东西,不把脑中的疑惑写明白,就感觉不到每天的进步。 每天没进步,这北漂生活,何时是个头啊。 可以北漂10年,也可以20年,但不可能是一辈子。 因为我不是北京人呐。 二、持续转…

Redis的字符串是怎么实现的

本篇会讲以下内容: Redis字符串的实现 Redis字符串的性能优势 Redis字符串的实现 Redis虽然是用C语言写的,但却没有直接用C语言的字符串,而是自己实现了一套字符串。目的就是为了提升速度,提升性能,可以看出Redis为…

Nacos的服务注册之客户端

服务注册到Nacos以后,会保存在一个本地注册表中,这个注册表是一个map. private Map<String, Map<String, Service>> serviceMap new ConcurrentHashMap<>(); key是namespace,用来隔离环境 value又是一个map      key是group      value又是一个s…

java计算机毕业设计springboot+vue远程教育系统

项目介绍 通篇文章的撰写基础是实际的应用需要,然后在架构系统之前全面复习大学所修习的相关知识以及网络提供的技术应用教程,以远程教育系统的实际应用需要出发,架构系统来改善现远程教育系统工作流程繁琐等问题。不仅如此以操作者的角度来说,该系统的架构能够对多媒体课程进…

以太网 DHCP(简介、DHCP工作原理、租期时间)

2.13.0 以太网 DHCP&#xff08;简介、DHCP工作原理、租期时间&#xff09; DHCP的作用&#xff1a;企业网络中存在大量的终端设备&#xff08;PC&#xff09;&#xff0c;管理员配置设备上网参数工作量大&#xff0c;而且效率不高&#xff0c;手动配置容易出错&#xff0c;DH…

数据库复杂sql如何编写入手

前言&#xff1a;说到数据库我想大家都不陌生&#xff0c;对主流的数据库都会基本使用&#xff0c;但是要写好sql完成复杂的sql编写是需要对数据库原理&#xff0c;sql脚本语法有一定的了解的&#xff0c;但是对于开发人员来说&#xff0c;平常都是在curd写一些业务代码&#x…

Flutter 中使用 OpenAI GPT-3 进行语义化处理

Flutter 中使用 OpenAI GPT-3 进行语义化处理 前言 最近 openai 的 ChatGPT 火了&#xff0c;然后我也想着用它来做点什么&#xff0c;于是就写了个 调用 openai api 语言执行工具&#xff0c;跑个测试&#xff0c;以后再有功能也可以在这个程序上面试验。 copilot 也是用的 op…

m基于FPGA的64QAM调制解调、载波同步verilog实现

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 64QAM&#xff08;正交幅度调制&#xff09;&#xff0c;在使用同轴电缆的网络中&#xff0c;这种数字频率调制技术通常用于发送下行链路数据。64QAM在6mhz信道中&#xff0c;64QAM的传输速率非常…

Qt编写视频监控系统(移动侦测/遮挡报警/区域入侵/越界侦测/报警输入输出等)

一、前言 得益于标准的onvif协议&#xff0c;各大监控厂商的设备都会支持onvif协议&#xff0c;在onvif协议中就包括了事件订阅机制&#xff0c;通过这个机制&#xff0c;可以拿到各种报警事件&#xff0c;比如移动侦测/遮挡报警/区域入侵/越界侦测/报警输入输出等&#xff0c…

深度学习-环境搭建(安装Pytorch)

文章目录前言一、安装Anaconda二、查看电脑显卡支持的CUDA版本三、更新CUDA版本四、创建并激活Anaconda虚拟环境需要创建虚拟环境而最好不在base下载的原因五、安装pytorchPS&#xff1a;注意事项六、下载其他库七、检查安装结果总结前言 入门深度学习过程中&#xff0c;我决定…

[附源码]JAVA毕业设计鞋店销售管理(系统+LW)

[附源码]JAVA毕业设计鞋店销售管理&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&…

都在说软件测试真的干不到35岁,那咋办呢...我都36了...

作为一个已经36岁但仍奋战在测试一线的老测试员&#xff0c;被人无数次问到这个问题&#xff0c;也回答过无数次&#xff0c;刚看到 程序员真的干到35岁就干不动了吗 想到&#xff0c;在测试行业&#xff0c;也有很多年轻人在焦虑这个问题。现在小编就从管理、技术、思维、体力…

Pytho——naiohttp的简单使用

1.aiohttp的简单使用(配合asyncio模块) import asyncio,aiohttpasync def fetch_async(url):print(url)async with aiohttp.request("GET",url) as r:reponse await r.text(encoding"utf-8")  #或者直接await r.read()不编码&#xff0c;直接读取&…

我不谈ChatGPT

&#xff08;1&#xff09;数据有两个未经证实的传闻&#xff1a;1、客服问答&#xff1a;80%用户问的问题都是那20%常见问题&#xff0c;但是就是这样&#xff0c;占用了客服人员80%的工作量和工作时间2、资讯搜索&#xff1a;谷歌一位员工说&#xff0c;在互联网上&#xff0…

Spring Cloud Alibaba-全面详解(学习总结---从入门到深化)

​​​​​​​ Spring Cloud Alibaba简介 什么是Spring Cloud Alibaba Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案。 此项目包含开发分布式应用微服务的必需组件&#xff0c;方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。 为…

OSI七层模型中各层网络协议

应用层: (典型设备:应用程序&#xff0c;如FTP&#xff0c;SMTP &#xff0c;HTTP) DHCP(Dynamic Host Configuration Protocol)动态主机分配协议&#xff0c;使用 UDP 协议工作&#xff0c;主要有两个用途&#xff1a;给内部网络或网络服务供应商自动分配 IP 地址&#xff0c…

spring——Spring 注入内部Bean——setter 方式注入内部 Bean

我们将定义在 <bean> 元素的 <property> 或 <constructor-arg> 元素内部的 Bean&#xff0c;称为“内部 Bean”。 项目依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org…

交战“低代码”,云大厂跑马圈地

者 关注 2022年末,云大厂阿里、腾讯、华为(ATH)开始了新一轮的跑马圈地。 这一次交战的战场,是低代码。 11月18日,华为AppCube全线产品全面升级,在低代码、零代码、数据看板三个方面,升级优化;11月13日,腾讯升级了云开发开发者工具“微搭”,目前已服务开发者数300万…