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

ops/2024/10/18 8:32:50/

 

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


今天给大家带来的是 【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() 方法获取写入的字节数组。
java hljs">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) 方法将数据读取到字节数组中。
java hljs">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() 方法将对象序列化
java hljs">public class Person implements Serializable { //一定要实现Serializable 接口才可以序列化和反序列化private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + "}";}
}
java hljs">public class ObjectOutputStreamExample {public static void main(String[] args) {try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 序列化后往哪个流里面写, 也可以是 FileOutputSteamObjectOutputStream 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() 方法获取对象。
java hljs">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 (文件流)来作为输出目的地和恢复的源头.


三、封装工具类

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

java hljs">/*** 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.ppmy.cn/ops/125034.html

相关文章

python 使用faker库 生成数据

Welcome to Faker’s documentation! — Faker 30.3.0 documentationVersion1: Example from docs:from faker import Faker from faker.providers import internet for i in range(2): #批量生成数据fake Faker()name fake.name()address fake.address()text f…

springMVC添加webapp

项目结构-->模块-->找到想添加的模块下的web 点击号 添加路径 会在.../src/main/目录下自动生成目录

5、Spring Boot 3.x 集成 RabbitMQ

一、前言 本篇主要是围绕着 Spring Boot 3.x 与 RabbitMQ 的集成,这边文章比较简单,RabbitMQ 的集成没有太大的变化,这篇文章主要是为了后续的 RabbitMQ 的动态配置做铺垫。 1、Docker 安装 RabbitMQ 2、Spring Boot 3.x 集成 RabbitMQ二、D…

如何解决与kernel32.dll相关的常见错误:详细指南解析kernel32.dll文件缺失、损坏或错误加载问题

当你的电脑中出现错误kernel32.dll丢失的问题,会导致电脑不能出现正常运行,希望能够有效的帮助你有效的将丢失的kernel32.dll文件进行修复同时也给大家介绍一些关于kernel32.dll文件的相关介绍,希望能够有效的帮助你快速修复错误。 kernel32.…

Flutter平台嵌入器

When you build a Flutter app, it’s not just about the code you write in Dart and the Flutter framework. There’s also a crucial piece called the platform embedders that enable your Flutter app to run on different operating systems like Android, iOS, and s…

(接口测试)day01接口测试理论 http理论 接口测试流程 接口文档解析

一.接口测试理论 1.接口和接口测试 服务器为客户端开了一个验证接口(接口本质:函数方法)客户端向服务器传送的消息可以相当于函数的参数,接口是用来让客户端传递数据的 接口:相当于开了一个通道 当服务器要给客户端响…

python-读写Excel:openpyxl-(3)单元格样式设置

目录 行高列宽 背景色 边框样式 字体样式 对齐样式 行高列宽 sht1.row_dimensions[5].height 20 # 设置指定行的行高 sht1.column_dimensions[a].width 15 # 设置指定列的列宽 背景色 fill_type属性决定了背景填充的类型,可以是none、solid、darkDown、…

Redis 消息队列:实现、操作与性能优化

Redis 是一个高性能的内存数据库,支持多种数据结构,特别适合用于实现消息队列。本文将详细介绍如何使用 Redis 的 List 数据结构实现一个简单而高效的消息队列系统,包括消息队列的基本操作、示例代码以及优化建议。 一,消息队列简…