【Java 基础篇】Java对象反序列化流详解

news2024/11/26 13:45:47

在这里插入图片描述

在Java编程中,对象序列化和反序列化是常见的操作,用于将对象转换为字节流以便于存储或传输,并从字节流中重新构建对象。本文将重点介绍对象反序列化流的用法和相关概念,帮助基础小白理解这一重要的主题。

什么是对象反序列化?

对象反序列化是将之前序列化的对象字节流还原为对象的过程。这个过程是序列化的逆过程,它可以让我们重新获得原始的Java对象,包括对象的状态和数据。反序列化是一种重要的机制,用于在Java中实现数据的持久化和跨网络通信。

对象反序列化的核心类是ObjectInputStream,它提供了一种方法来读取已序列化的对象数据并将其还原为Java对象。

ObjectInputStream的基本用法

要使用ObjectInputStream,首先需要创建一个输入流并将其连接到包含序列化对象的数据源,通常是一个文件或网络连接。接下来,您可以使用ObjectInputStream来读取对象。

下面是一个基本的对象反序列化示例:

import java.io.*;

public class ObjectDeserializationExample {
    public static void main(String[] args) {
        try {
            // 创建一个输入流,连接到包含序列化对象的文件
            FileInputStream fileIn = new FileInputStream("serializedObject.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);

            // 使用ObjectInputStream读取对象
            MyClass deserializedObject = (MyClass) in.readObject();

            // 关闭流
            in.close();
            fileIn.close();

            // 使用反序列化后的对象
            System.out.println("Deserialized Object: " + deserializedObject);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

上述示例中,我们使用FileInputStream将对象反序列化流连接到一个包含序列化对象的文件。然后,我们使用ObjectInputStreamreadObject方法来读取对象,并将其强制转换为原始的Java对象。

Serializable接口和版本控制

在进行对象序列化和反序列化时,需要确保被操作的类实现了Serializable接口。这个接口是一个标记接口,没有定义任何方法,但它告诉Java运行时系统这个类可以进行序列化。

import java.io.Serializable;

public class MyClass implements Serializable {
    // 类的成员和方法
}

另一个重要的考虑因素是版本控制。当您对一个已序列化的类进行更改时,特别是在类的字段或结构发生变化时,可能会导致版本不兼容。为了处理版本兼容性问题,可以在类中显式定义serialVersionUID,如下所示:

private static final long serialVersionUID = 123456789L;

通过显式定义serialVersionUID,您可以确保在反序列化时可以与之前的版本兼容。如果没有提供serialVersionUID,Java会根据类的结构自动生成版本号,这可能会导致反序列化失败。

自定义序列化与writeObjectreadObject方法

有时,您可能需要自定义对象的序列化和反序列化过程,以满足特定需求。您可以在类中定义以下两个方法:

  • private void writeObject(ObjectOutputStream out) throws IOException:这个方法在对象序列化时自动被调用。您可以在其中编写自定义的序列化逻辑。
  • private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException:这个方法在对象反序列化时自动被调用。您可以在其中编写自定义的反序列化逻辑。

这两个方法的签名必须与上述示例中的一致。

序列化的性能和安全性考虑

尽管对象序列化和反序列化是强大的工具,但在性能和安全性方面需要谨慎。以下是一些性能和安全性方面的考虑:

性能考虑

  • 序列化和反序列化可能是昂贵的操作,特别是对大型对象或大量对象的处理。要谨慎使用它们,以避免性能问题。
  • 考虑使用更轻量级的序列化格式,如JSON或Protocol Buffers,以提高性能。

安全性考虑

  • 反序列化操作可能存在安全风险,因为恶意用户可以创建恶意的序列化数据。要确保只反序列化来自受信任源的数据,并对反序列化的数据进行有效验证。
  • 考虑使用安全的序列化机制,如Java的序列化过滤器或自定义的反序列化控制,以减少安全风险。

常用示例

当涉及对象反序列化时,通常有以下几个常见的应用场景。以下是一些示例:

1. 从文件中加载配置数据

假设您的应用程序需要读取和加载配置数据,您可以使用对象序列化来将配置对象保存到文件中。然后,在应用程序启动时,您可以使用对象反序列化从文件中加载配置数据。这可以帮助您在不更改代码的情况下轻松更改和管理配置。

// 序列化配置数据到文件
public static void serializeConfiguration(Configuration config) {
    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("config.ser"))) {
        out.writeObject(config);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// 从文件中反序列化配置数据
public static Configuration deserializeConfiguration() {
    try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("config.ser"))) {
        return (Configuration) in.readObject();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
        return null;
    }
}

2. 缓存对象

有时,您可能希望将一些对象缓存到磁盘上,以便稍后重新加载它们,而不是每次都重新生成它们。对象序列化和反序列化可用于实现此功能。

// 序列化对象到缓存文件
public static void serializeToCache(Object object, String cacheKey) {
    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(cacheKey))) {
        out.writeObject(object);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// 从缓存文件中反序列化对象
public static Object deserializeFromCache(String cacheKey) {
    try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(cacheKey))) {
        return in.readObject();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
        return null;
    }
}

3. 跨网络传输对象

在分布式系统中,您可能需要将对象从一个地方传输到另一个地方。对象序列化可用于将对象转换为字节流,并在网络上传输,然后在接收端进行反序列化。

// 服务器端 - 序列化并发送对象
try (ServerSocket serverSocket = new ServerSocket(12345)) {
    while (true) {
        Socket clientSocket = serverSocket.accept();
        ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream());
        out.writeObject(myObject);
        out.close();
        clientSocket.close();
    }
} catch (IOException e) {
    e.printStackTrace();
}

// 客户端 - 接收并反序列化对象
try (Socket socket = new Socket("server-hostname", 12345)) {
    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
    MyObject receivedObject = (MyObject) in.readObject();
    in.close();
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

4. 数据持久化

对象序列化还可以用于数据持久化,特别是在应用程序需要长期存储和恢复数据时。例如,您可以使用对象序列化将用户的应用程序状态保存在文件中,以便在下一次启动应用程序时恢复该状态。

// 序列化应用程序状态到文件
public static void serializeAppState(AppState state) {
    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("appstate.ser"))) {
        out.writeObject(state);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// 从文件中反序列化应用程序状态
public static AppState deserializeAppState() {
    try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("appstate.ser"))) {
        return (AppState) in.readObject();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
        return null;
    }
}

5. 消息传递

在分布式系统中,消息传递是一种常见的通信方式。对象序列化和反序列化可用于将消息封装为对象,并在系统的不同部分之间传递消息。

// 发送方 - 序列化消息并发送
Message message = new Message("Hello, world!");
try (Socket socket = new Socket("server-hostname", 12345)) {
    ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
    out.writeObject(message);
    out.close();
} catch (IOException e) {
    e.printStackTrace();
}

// 接收方 - 接收并反序列化消息
try (ServerSocket serverSocket = new ServerSocket(12345)) {
    while (true) {
        Socket clientSocket = serverSocket.accept();
        ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
        Message receivedMessage = (Message) in.readObject();
        in.close();
        clientSocket.close();
        // 处理接收到的消息
    }
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

这些示例涵盖了对象反序列化的几个常见用途场景,包括配置管理、对象缓存、跨网络传输、数据持久化和消息传递。通过对象序列化,您可以在不同的上下文中轻松地传输、存储和加载对象数据。

总结

对象反序列化是Java中重要的编程概念,用于将序列化的对象还原为原始的Java对象。通过了解ObjectInputStream的基本用法、Serializable接口、版本控制、自定义序列化和性能、安全性考虑,您可以更好地使用和理解对象反序列化流。但请谨慎使用它,特别是在面临性能和安全性问题时。

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

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

相关文章

javaee之黑马乐优商城4

商品规格与数据结构 下面来说一下数据库的设计与分析 其实对于spu这张表来说,大体设计还是比较好设计的 看一下下面这张图是一个产品的规格参数 上面主体就是一个规格参数,基本信息又是一个规格参数 这里就是涉及到了一个商品的具体信息,sku…

在时代的浪潮中实在前行!实在智能与浪潮通软全面开启战略合作

“新”潮涌动,浪花朵朵。近日,杭州实在智能科技有限公司与浪潮通用软件有限公司签署战略合作协议。双方将加快科研创新,扩大合作领域,共同开拓数智化市场,携手共赢。 浪潮通软平台软件与技术研究院总经理周祥国、实在智…

游戏使用脚本配置HTTP

在游戏世界中,使用脚本工具帮助优化游戏体验已经成为一种普遍现象。但是,是否需要结合代理IP来使用游戏脚本呢?本文将探讨游戏使用脚本时是否需要代理IP的利弊,并分享合规使用脚本的方法。 1. 提高账号安全性: - 通过…

知识图谱的搭建

知识图谱搭建最重要的核心在于对业务的理解以及对知识图谱本身的设计,这就类似于对于一个业务系统,数据库表的设计是至关重要的,而这种设计师根据业务及未来场景的变化预估不断探索得出的。 一个完整的知识图谱的构建包含以下几个步骤&#…

Spring 中的Aware接口有什么作用

文章目录 0.前言1.什么是Aware接口2.Aware接口的设计目的3.详解3.1. ApplicationContextAware我们举个例子来说明 3.2. BeanFactoryAware3.3. BeanNameAware3.4. ServletContextAware3.5. MessageSourceAware3.6. ResourceLoaderAware 4.参考文档 0.前言 背景: 最近…

Centos7完全离线环境安装Nvidia Tesla A100 40G显卡驱动(含CUDA Toolkit)和Anaconda3虚拟环境

公司一台完全离线环境的服务器刚装了Nvidia Tesla A100 40G显卡,自己摸索着将显卡驱动在完全离线环境下安装成功,这里记录一下。 一、下载Centos7适配的Nvidia Tesla A100 40G显卡驱动 在Nvidia官网下载Centos7适配的显卡驱动,CUDA Toolkit…

idea(第一次)启动项目,端口变成了8080

先上配置 server:port: 9569 spring:profiles:active: dev 该排查的问题也都没问题,重启idea也试过了,还是8080 解决办法:点击右侧的maven ,左上角的重新导入 reimport all maven projects 我又没有改动pom文件,居然还要点这…

玩机教程:阿里云无影云电脑怎么使用?

阿里云无影云电脑即无影云桌面,云电脑如何使用?云电脑购买后没有用户名和密码,先创建用户设置密码,才可以登录连接到云桌面。云桌面想要访问公网还需要开通互联网访问功能。阿里云百科来详细说下阿里云无影云电脑从购买、创建用户…

Android 13.0 SystemUI下拉状态栏背景增加高斯模糊背景

1.概述 在13.0的产品开发中,发现现在很多产品都是高斯模糊背景的,这种高斯模糊背景看起来效果很不错,产品开发需要SystemUI下拉状态栏背景也是高斯模糊背景,所以就要来实现下拉状态栏高斯模糊背景 2.SystemUI 下拉状态栏背景增加高斯模糊背景核心类 frameworks/base/pack…

python后端和前端通过websocket通讯发消息最小案例,十分钟看懂

前端和后端通过websocket实现发送消息案例,用于理解websocket,服务端可以主动给客户端发送消息,而且是长连接,比http效率高,因为http要不断地创建和销毁socket实例,导致压力很大。websocket一次创建&#x…

自定义类型:结构体----初学者笔记

目录 1. 结构体类型的声明 1.1 结构体类型的简单介绍和声明 1.1.1 结构的声明 1.1.2 特殊的声明 1.1.3 结构的自引用 2. 结构体变量的创建和初始化 3. 结构成员访问操作符 4. 结构体内存对⻬ 4.1 对齐规则 4.2 练习 4.2.1 练习1 4.2.2 练习2 4.3 为什么存在内存对…

知名IT网站博客园陷入绝境

我是卢松松,点点上面的头像,欢迎关注我哦! 博客园陷入生死存亡的绝境。 5月份知名IT开发者网站发布文章称“博客园网站遇到困难了:寻求捐助”,并开通了捐助渠道。4个月过去了,好像效果并不明显&#xff…

婚庆行业类软文怎么写?媒介盒子无偿分享

随着我国经济发展以及对婚礼品质要求的提升,结婚相关的市场发展愈发强劲,由于互联网发展的快速性,大部分新人选择通过网络获取结婚服务信息,所以线上成为婚庆公司的主要获客渠道。而软文营销就是婚庆公司提升品牌形象的主要方式&a…

AI写作工具,智能ai写作工具

在信息化时代,内容创作已经成为了许多行业的核心。从营销广告到新闻报道,从博客文章到学术论文,人们需要不断地产生高质量的文字内容。创作是一项耗时耗力的工作,需要丰富的知识和创造性思维。 AI写作工具,是一类基于人…

docker容器技术实战-3

08 docker 原生网络 原生网络:桥接模式 :生成虚拟网络对 host模式:容器和宿主机共享同一网络栈,不会新建虚拟网卡 none禁用网络:只用回环接口 自定义接口:内嵌dns解析 不同网络之间是被隔离的,默认不能通…

【C++】map与set的封装

文章目录 前言正文1. 类型的泛化2.仿函数3.迭代器3.1正向迭代器3.1.1 3.1.2 - -3.1.3 *3.1.4 ->3.1.5 !完整版代码 4.[](map) 框架1.红黑树2.set3.map 总结 前言 在学习了红黑树之后,我们便可以尝试初步的在红黑树的基础上封装出map与set&…

Python日志处理器,同时打印到控制台和保存到文件中,并保证格式一致

使用logging模块的时候,默认是输出到控制台的,当然也可以配置输出到文件中,但是当你配置了文件后,控制台的输出就消失了,所以,需要一个策略即能保存到文件中,又能输出到控制台中。 下面是我做的…

ORB-SLAM2实时稠密地图,解决运行报段错误(核心已转储)运行数据集时出现段错误,出现可视化界面后闪退(添加实时彩色点云地图+保存点云地图)

高翔的稠密建图仓库 1. git clone https://github.com/gaoxiang12/ORBSLAM2_with_pointcloud_map.git 2. 去ORB SLAM2里拷贝Vocabulary到/home/cgm/ORBSLAM2_with_pointcloud_map/ORB_SLAM2_modified文件夹下 3. 删除一些build文件夹 删除ORB_SLAM2_modified/Thirdparty/DB…

国产手机芯片4G方案_紫光展锐安卓核心板虎贲4G智能模块方案定制

元器件清单即BOM物料清单,不同行业领域的BOM表侧重点不一样。安卓主板的BOM表则侧重点在于元器件物料的清单,也就是安卓电路板的PCBA清单,精密的安卓板有上千个物料,可以帮助我们估算物料成本,建立生产计划&#xff0c…

Ftp服务器、 Samba服务器、NFS服务器的区别

根据使用的方式来看,可以分为3种类别的文件服务器:ftp服务器(ftp/tftp)、 Samba服务器、NFS服务器。ftp的客户可以是任意平台,samba是专门针对windows客户,而NFS则是面向linux/unix用户的。下面是三种服务器…