【Java IO流】对象与字节流的序列化和反序列化

news2024/12/27 13:03:20

 

哈喽,哈喽,大家好~ 我是你们的老朋友:保护小周ღ  


今天给大家带来的是 【Java IO流】对象与字节流的序列化和反序列化,首先了解, 本次主题有啥实际应用, 学习 ByteArrayOutputStream / ByteArrayInputStream 字节数组流, ObjectOutputStream / ObjectInputStream 对象与字节流的序列化和反序列化 , 前者作为当期流的输出目的, 和数据来源,  一起来看看叭~

本期收录于博主的专栏:JavaSE_保护小周ღ的博客-CSDN博客

适用于编程初学者,感兴趣的朋友们可以订阅,查看其它 “JavaSE基础知识”。

更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* ‘ 


对象与字节流的序列化和反序列化在 Java 开发中具有重要作用,主要用于将对象状态转换为字节流以便存储或传输。以下是它们的一些作用介绍:

作用

  1. 持久化存储:

    • 将对象的状态保存到文件或数据库,以便在系统重启时恢复。
    • 例如,将用户设置、游戏进度等信息保存到磁盘。
  2. 网络传输:

    • 在分布式系统或者微服务架构中,通过网络发送对象,以实现远程通信。
    • 例如,使用 RMI(远程方法调用)或者 gRPC 进行服务间调用时,需要传输对象。
  3. 深拷贝:

    • 创建对象的深拷贝,避免引用类型字段造成的共享问题。
    • 例如,在需要保护原始对象不被修改时,可以通过序列化和反序列化来复制对象。
  4. 缓存:

    • 将对象序列化后存储在内存中,减少重复计算,提高性能。
    • 例如,使用 Redis 等缓存工具时,可以序列化对象以便快速读取

一、处理字节数组的流类

ByteArrayOutputStreamByteArrayInputStream 是 Java 中用于处理字节数组的流类,通常用于输入和输出操作。

1.1 ByteArrayOutputStream

功能

  • ByteArrayOutputStream 允许你将数据写入一个字节数组中,而不是直接写入文件或其他输出流。
  • 这个类提供了一个可动态扩展的字节数组,可以随时获取当前写入的数据。

用法

  • 创建一个 ByteArrayOutputStream 流对象。
  • 使用 write() 方法将字节写入到流中。
  • 调用 toByteArray() 方法获取写入的字节数组。
public class ByteArrayOutputStreamExample {
    public static void main(String[] args) {
        // 这种将流对象写在 try 中的写法, 这种结构确保在操作完成后,相关的资源(如流)会被自动关闭,从而避免内存泄漏。
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            String data = "Hello, World!";
            // getBytes() 方法就是将字符串转换为字节数组, 写入流对象
            bos.write(data.getBytes());

            // 获取字节数组
            byte[] byteArray = bos.toByteArray();
            System.out.println("Written bytes: " + new String(byteArray));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


1.2 ByteArrayInputStream

功能

  • ByteArrayInputStream 允许你从一个字节数组中读取数据。
  • 可以用来在内存中模拟输入流操作,方便进行数据处理。

用法

  • 创建一个 ByteArrayInputStream 对象,并传入一个字节数组。
  • 使用 read() 方法读取字节,或者使用 read(byte[] b) 方法将数据读取到字节数组中。
public class ByteArrayInputStreamExample {
    public static void main(String[] args) {
        byte[] inputData = "Hello, World!".getBytes();

        try (ByteArrayInputStream bis = new ByteArrayInputStream(inputData)) {
            int data;
            int count = 0;
            while ((data = bis.read()) != -1) {
                count++;
                System.out.print((char) data); // 转换为字符并打印
            }
            System.out.println();
            // 说明一次读取四个字节, 但是也需要读取 13 次, Hello, World! 13个字符
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


 二、序列化与反序列化的流类

ObjectOutputStreamObjectInputStream 是 Java 中用于对象的序列化与反序列化的流类。这两个类使得将对象写入流并从流中读取对象变得非常简单。

注意:若是想一个类可具备序列化和反序列化的能力,需要该类实现 Serializable 接口。

  • 只序列化可序列化的成员变量。如果某个字段不需要序列化,可以使用 transient 关键字修饰该字段。
  • 如果类的结构发生变化(如修改了字段),可能会导致反序列化失败,这时可以使用 serialVersionUID 来版本控制。

2.1 ObjectOutputStream

功能

  • ObjectOutputStream 可用于将 Java 对象序列化为字节流,以便存储或通过网络传输。
  • 它将对象的状态(包括对象的属性)转换为字节序列。

用法

  1. 创建一个 FileOutputStream(文件流) 以指定输出目的地(如文件)。
  2. 创建一个 ByteArrayOutputStream(字节数组)  就可以输出到字节数组啦。
  3. 使用 ObjectOutputStream 将对象写入到流中。
  4. 调用 writeObject() 方法将对象序列化。
public class Person implements Serializable { //一定要实现Serializable 接口才可以序列化和反序列化
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}
public class ObjectOutputStreamExample {
    public static void main(String[] args) {
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 序列化后往哪个流里面写, 也可以是 FileOutputSteam
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) { // 这种写法可以自动关闭资源

            Person person = new Person("Alice", 30);
            objectOutputStream.writeObject(person); // 序列化对象
            System.out.println("Object serialized: " + person);
            // 存储在字节数据流中, 以字节数组的形式输出
            System.out.println(Arrays.toString(byteArrayOutputStream.toByteArray()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


2.2 ObjectInputStream

功能

  • ObjectInputStream 用于从字节流中反序列化对象,即读取序列化后的对象数据并恢复成 Java 对象。

用法

  1. 创建一个 FileInputStream (文件流) 指向序列化对象的文件。
  2. 创建一个 ByteArrayInputStream(字节数组)指向序列化对象的字节数组流。
  3. 使用 ObjectInputStream 从流中读取对象。
  4. 调用 readObject() 方法获取对象。
public class ObjectInputStreamExample {
    public static void main(String[] args) {
        // 用于存储 Person 对象序列化后字节
        byte[] personBytes = new byte[0];

        // 1. 先将 Person 对象序列化为字节数组
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) { // 这种写法可以自动关闭资源

            Person person = new Person("Alice", 30);
            objectOutputStream.writeObject(person); // 序列化对象
            System.out.println("Object serialized: " + person);
            // 存储在字节数据流中, 以字节数组的形式输出
            byte[] data = byteArrayOutputStream.toByteArray();
            personBytes = new byte[data.length];
            personBytes = byteArrayOutputStream.toByteArray();

            System.out.println(Arrays.toString(personBytes));
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 2. 将字节数组personBytes, 反序列化为 person 对象
        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(personBytes); // 从哪个字节数组中读取
             ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {

            Person person = (Person) objectInputStream.readObject();// 反序列化对象
            System.out.println("----------------------------------");
            System.out.println("Object deserialized: " + person);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


总结

  • 序列化:使用 ObjectOutputStream 将对象转化为字节流,可以存储或传输。
  • 反序列化:使用 ObjectInputStream 从字节流中恢复对象状态。

这两个类主要用于持久化对象,确保对象状态可以在不同的程序运行间保存和恢复。注意,参与序列化的对象必须实现 Serializable 接口。

且序列化/ 反序列化的字节流也可以使用 FileOutputStream 和 FileInputStream (文件流)来作为输出目的地和恢复的源头.


三、封装工具类

根据上述所讲, 我们可以将一个对象序列化为字节流, 也可以将字节流序列化为对象. 那我们就可以在开发中针对上述方法进行封装使用.

/**
 * Created with IntelliJ IDEA.
 * Description: 二进制序列化工具
 * Author: 保护小周
 * Date: 2024-08-21
 * Time: 23:22
 */
public class BinaryTool {

    /**
     * 把一个对象序列化成一个字节数组
     * @param object
     * @return
     */
    public static byte[] toBytes(Object object) throws IOException {
        // 这个流对象相当于一个变长的字节数组.
        // 就可以把 object 序列化的数据给逐渐的写入到 byteArrayOutputStream 中, 再统一转成 byte[]
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
            try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
                // 此处的 writeObject 就会把该对象进行序列化, 生成的二进制字节数据, 就会写入到
                // ObjectOutputStream 中.
                // 由于 ObjectOutputStream 又是关联到了 ByteArrayOutputStream, 最终结果就写入到 ByteArrayOutputStream 里了
                objectOutputStream.writeObject(object);
            }
            // 这个操作就是把 byteArrayOutputStream 中持有的二进制数据取出来, 转成 byte[]
            return byteArrayOutputStream.toByteArray();
        }
    }

    /**
     * 把一个字节数组, 反序列化成一个对象
     * @param data
     * @return
     */
    public static Object fromBytes(byte[] data) throws IOException, ClassNotFoundException {
        Object object = null;
        // 这个流对象相当于一个边长的字节数组
        // 就可以把object 序列化的数据给逐渐的写入到 byteArrayOutStream.
        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)) {
            try (ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {
                // 此处的 readObject 就是从 data 这个 byte[] 中读取数据并进行反序列化.
                 object = objectInputStream.readObject();
            }
        }
        return object;
    }
}

 实际应用效果展示: 非常的实用呀~


 好了,到这里,【Java IO流】对象与字节流的序列化和反序列化 博主已经分享完了,阐述较为基础,  希望对大家有所帮助,如有不妥之处欢迎批评指正。 

感谢每一位观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* 

遇见你,所有的星星都落在我的头上……

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

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

相关文章

微信开发者工具:音乐小程序报错

报错信息 GET http://localhost:3000/1.mp3 net::ERR CONNECTION REFUSED (env: Windows,mp,1.06.2303220;lib:3.6.0) 原因:小程序没有直接获取本地文件,为了提高访问速度,而采用放到网络服务器中网络访问的方式获取文件内容 解决办法&#…

H7-TOOL的LUA小程序教程第14期:任意波形信号发生器,0-20mA输出和微型数控电源(2024-10-11,已更新)

LUA脚本的好处是用户可以根据自己注册的一批API(当前TOOL已经提供了几百个函数供大家使用),实现各种小程序,不再限制Flash里面已经下载的程序,就跟手机安装APP差不多,所以在H7-TOOL里面被广泛使用&#xff…

空间解析几何3-空间点到线段和平面的距离【附MATLAB代码】

目录 空间中点到线段的距离 空间中点到平面的投影和距离 matlab代码 空间中点到线段的距离 空间中点到平面的投影和距离 matlab代码 function [dis,P2,t] point2Line (A1,B1,C1) %求空间一点到一线段的最短距离 %[dis,P2,Q2]pointSegmentDistance(A,B,C) %A B为线段首末端…

【安当产品应用案例100集】021- 针对电网接入设备的控制指令安全解决方案

一、电网对接入设备的控制指令安全体现在哪些方面 电网接入设备的控制指令安全必要性不言而喻。为了保障电网的稳定运行、防止恶意攻击和破坏、提升电网智能化水平、满足法律法规和监管要求以及提升用户满意度和社会形象,必须加强电网接入设备的控制指令安全管理。…

2.html编辑器介绍

html编辑器介绍 HTML 编辑器推荐 理论上我们可以使用记事本进行html编码和开发,但是在实际开发html页面的时候,使用一些专业的开发工具可以使我们更加快速和高效的进行开发,下面介绍几种开发工具: VS Code:https://…

UE5 C++ 通过绑定编辑器事件实现控制柄顶点编辑

开发中经常会遇到编辑器环境中制作工具拖拽控制柄编辑内容的需求,此时可以通过Editor事件拿到对应回调,进行相应更新: 1.创建Mesh编辑Actor类 创建一个Mesh编辑Actor类,提供Mesh顶点编辑的相关逻辑。 .h: #pragma once#inclu…

机器人的应用 基于5G的变电站智慧管控系统

背景概述 一、电力行业面临的挑战与变革 随着全球工业化和信息化的快速发展,电力行业作为国民经济的基础性行业,其重要性日益凸显。然而,随着电力网络的不断扩展和复杂化,变电站和开关站作为电力传输与分配的关键节点&#xff0…

jdk环境变量配置--小总结

1、jdk安装路径变量 2、在path下添加环境变量

dbt doc 生成文档命令示例应用

DBT提供了强大的命令行工具,它使数据分析师和工程师能够更有效地转换仓库中的数据。dbt的一个关键特性是能够为数据模型生成文档,这就是dbt docs命令发挥作用的地方。本教程将指导您完成使用dbt生成和提供项目文档的过程。 dbt doc 命令 dbt docs命令有…

大模型生图安全疫苗注入赛题解析(DataWhale组队学习)

引言 大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年10月实践赛的大模型生图安全疫苗注入赛道;本文主要整理本次赛事的基本流程和优化方法。💕💕😊 一…

Qt:图片文字转base64程序

目录 一.Base64 1.编码原理 2.应用场景 3.优点 4.限制 5.变种 二.文字与Base64互转 1.ui设计 2.文字转Base64 3.Base64转文字 三.图片与Base64互转 1.ui设计 2.选择图片与图片路径 3.图片转Base64 4.Base64转图片 四.清空设置 五.效果 六.代码 base64conver…

第二十三篇:网络拥塞了,TCP/IP如何解决的?

一.显示拥塞通知 当发生网络拥塞时,发送主机应该减少数据包的发送量。作为IP上层协议,TCP虽然也能控制网络拥塞,不过它是通过数据包的实际损坏情况来判断是否发生拥塞。然而这种方法不能在数据包损坏之前减少数据包的发送量。 为了解决这个…

linux下使用mpi求自然数和

搭建MPI并行计算环境,编写 MPI程序,求和 1 23....1 0000。 要求: 1.使用100个进程; 2.进程0计算1 2...100, 进程1计算101 102... 200, ..... 进程99计算9901 9902... 10000; 3.调用计时函数,分别输出每个进程的计算时间; 4.需使用MPI集群通信函数和同…

三、ElementPlus下拉搜索加弹窗组件的封装

近期产品提出了一个需求,要求一个form的表单里面的一个组件既可以下拉模糊搜索,又可以弹窗搜索,我就为这个封装了一个组件,下面看效果图。 效果大家看到了,下面就看组件封装和实现方法 第一步,组件封装&…

第1章 开发板功能及使用介绍

1.开发板功能及使用介绍 本章主要内容 1.开发板功能介绍 2.开发板使用方法 介绍 STM32介绍 本章主要内容: 1.什么是STM32 2.STM32与ARM的关系 3.STM32F407ZGT6介绍 4.STM32能做什么 1.什么是STM32 从字面意义来看: ST:意法半导体&#xf…

HarmonyOS NEXT 应用开发实战(三、ArkUI页面底部导航TabBar的实现)

在开发HarmonyOS NEXT应用时,TabBar是用户界面设计中不可或缺的一部分。本文将通过代码示例,带领大家一同实现一个常用的TabBar,涵盖三个主要的内容页:首页、知乎日报和我的页面。以模仿知乎日报的项目为背景驱动,设定…

【Spring AI】Java实现类似langchain的第三方函数调用_原理与详细示例

Spring AI 介绍 :简化Java AI开发的统一接口解决方案 在过去,使用Java开发AI应用时面临的主要困境是没有统一且标准的封装库,导致开发者需要针对不同的AI服务提供商分别学习和对接各自的API,这增加了开发难度与迁移成本。而Sprin…

Android常用界面控件——ProgressBar

ProgressBar 目录 ProgressBar 在XML中定义ProgressBar ProgressBar风格样式 ProgressBar常用XML属性 在Java代码中控制ProgressBar 实例 什么是ProgressBar? ProgressBar是Android中的一个视图控件,主要用于表示一个任务的进度情况,…

针对Ubuntu20.04 中的 Docker 配置可用镜像源(包含国内可用镜像源)

文章目录 写在前面一、Docker 官方源二、更换Docker 国内可用镜像源 (推荐使用)参考链接 写在前面 自己的测试环境: Ubuntu20.04,docker-27.3.1 一、Docker 官方源 打开 /etc/docker/daemon.json文件: sudo gedit …

Python快速编程小案例--逢7拍手小游戏

提示:(个人学习),案例来自工业和信息化“十三五”人才培养规划教材,《Python快速编程入门》第2版,黑马程序员◎编著 逢7拍手游戏的规则是:从1开始顺序数数,数到有7或者包含7的倍数的…