当前位置: 首页 > article >正文

Java 序列化和反序列化为什么要实现Serializable接口

1. 什么是序列化和反序列化

  • 序列化:将对象的状态信息转换为可以存储或传输的形式(通常是字节序列)的过程。例如,将一个 Java 对象保存到文件中或者通过网络发送给其他程序。

  • 反序列化:将字节序列恢复为对象的过程。比如,从文件中读取字节序列并将其转换为 Java 对象。

2. 为什么要实现 Serializable 接口

Serializable 接口是一个标记接口,它本身不包含任何方法。其作用是告诉 Java 虚拟机(JVM)该类的对象可以被序列化。当一个类实现了 Serializable 接口,就相当于给这个类打上了一个 “可以被序列化” 的标记。JVM 在进行序列化操作时,会检查对象所属的类是否实现了 Serializable 接口,如果没有实现,就会抛出 NotSerializableException 异常。

示例代码:

import java.io.*;// 实现 Serializable 接口
class Person implements Serializable {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}
}public class SerializationExample {public static void main(String[] args) {Person person = new Person("Alice", 25);// 序列化try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {oos.writeObject(person);System.out.println("对象已序列化");} catch (IOException e) {e.printStackTrace();}// 反序列化try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {Person deserializedPerson = (Person) ois.readObject();System.out.println("对象已反序列化");System.out.println("Name: " + deserializedPerson.getName());System.out.println("Age: " + deserializedPerson.getAge());} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}

代码中,Person 类实现了 Serializable 接口,因此可以对其对象进行序列化和反序列化操作。

3. 除了Serializable接口,还有哪些方式可以控制Java对象的序列化?

1. 使用 transient 关键字

transient 关键字用于修饰类的成员变量,被 transient 修饰的变量在序列化过程中会被忽略,即不会被保存到字节流中。在反序列化时,这些变量会被赋予默认值(如 null 、0 等)。

示例代码

import java.io.*;class User implements Serializable {private String username;private transient String password;public User(String username, String password) {this.username = username;this.password = password;}public String getUsername() {return username;}public String getPassword() {return password;}
}public class TransientExample {public static void main(String[] args) {User user = new User("admin", "123456");try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"));ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) {oos.writeObject(user);User deserializedUser = (User) ois.readObject();System.out.println("Username: " + deserializedUser.getUsername());System.out.println("Password: " + deserializedUser.getPassword());} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
2. 使用 Externalizable 接口

Externalizable 接口继承自 Serializable 接口,它要求实现类必须重写 writeExternal 和 readExternal 方法,通过这两个方法可以完全自定义对象的序列化和反序列化过程。

import java.io.*;class Book implements Externalizable {private String title;private int year;// 必须有一个无参构造函数public Book() {}public Book(String title, int year) {this.title = title;this.year = year;}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject(title);out.writeInt(year);}@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {title = (String) in.readObject();year = in.readInt();}public String getTitle() {return title;}public int getYear() {return year;}
}public class ExternalizableExample {public static void main(String[] args) {Book book = new Book("Java Programming", 2023);try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("book.ser"));ObjectInputStream ois = new ObjectInputStream(new FileInputStream("book.ser"))) {oos.writeObject(book);Book deserializedBook = (Book) ois.readObject();System.out.println(deserializedBook.getTitle() + " - " + deserializedBook.getYear());} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
3. 自定义 writeObject 和 readObject 方法

在实现 Serializable 接口的类中,可以定义私有方法 writeObject 和 readObject 来定制序列化和反序列化的逻辑。当 Java 进行序列化和反序列化操作时,会自动调用这两个方法。

import java.io.*;class Product implements Serializable {private String name;private double price;public Product(String name, double price) {this.name = name;this.price = price;}private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();// 可以添加额外的序列化逻辑out.writeDouble(price * 0.9); // 序列化打折后的价格}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();// 可以添加额外的反序列化逻辑price = in.readDouble();}public String getName() {return name;}public double getPrice() {return price;}
}public class CustomSerializationExample {public static void main(String[] args) {Product product = new Product("Laptop", 1000);try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("product.ser"));ObjectInputStream ois = new ObjectInputStream(new FileInputStream("product.ser"))) {oos.writeObject(product);Product deserializedProduct = (Product) ois.readObject();System.out.println(deserializedProduct.getName() + " - $" + deserializedProduct.getPrice());} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
4. 使用 writeReplace 和 readResolve 方法

writeReplace 方法允许在序列化之前替换要序列化的对象,而 readResolve 方法允许在反序列化之后替换反序列化得到的对象。这两个方法可以用于实现单例模式的序列化和反序列化,确保单例的唯一性。

import java.io.*;class Singleton implements Serializable {private static final Singleton INSTANCE = new Singleton();private Singleton() {}public static Singleton getInstance() {return INSTANCE;}private Object writeReplace() throws ObjectStreamException {return INSTANCE;}private Object readResolve() throws ObjectStreamException {return INSTANCE;}
}public class ReplaceExample {public static void main(String[] args) {try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton.ser"));ObjectInputStream ois = new ObjectInputStream(new FileInputStream("singleton.ser"))) {oos.writeObject(Singleton.getInstance());Singleton deserializedSingleton = (Singleton) ois.readObject();System.out.println(Singleton.getInstance() == deserializedSingleton); // 输出 true} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}

这些方式可以根据不同的需求灵活控制 Java 对象的序列化过程,以满足安全性、性能等方面的要求。

相关文章:

Java 序列化和反序列化为什么要实现Serializable接口

1. 什么是序列化和反序列化 序列化:将对象的状态信息转换为可以存储或传输的形式(通常是字节序列)的过程。例如,将一个 Java 对象保存到文件中或者通过网络发送给其他程序。 反序列化:将字节序列恢复为对象的过程。比…...

java虚拟机(JVM)以及各种参数详解

Java 虚拟机&#xff08;JVM&#xff09;提供了许多参数来调整其行为和性能&#xff0c;以便更好地适应不同的应用场景。理解和使用这些参数对于优化 Java 应用程序的性能非常重要。以下是一些常用的 JVM 参数及其详细说明&#xff1a; 1. 内存管理参数 -Xms<size>&…...

微信小程序审核失败,你的小程序涉及提供播放、观看等服务,请补充选择:文娱-其他视频类目 解决

之前审核的都没有什么问题&#xff0c;结果这次就不给过还提示我们这个。 我们的视频是操作演示的视频。仅用于介绍使用。 是否接受修改指引&#xff0c;勾选我不理解以上内容 再勾选 下面不理解内容异项 申诉理由 视频播放和观看只限于当前用户自己使用&#xff0c;而视…...

电力行业研究系列报告

欧洲风能&#xff1a;2024年统计数据及2025-2030年展望 固态电池全景图&#xff1a;方兴未艾&#xff0c;技术竞逐 电力设备新能源2025年3月投资策略&#xff1a;固态电池产业加速推进&#xff0c;关注GTC大会HVDC电源产品应用趋势 62页PPT了解国内外40家固态电池典型企业技…...

蓝桥杯嵌入式组第七届省赛题目解析+STM32G431RBT6实现源码

文章目录 1.题目解析1.1 分而治之&#xff0c;藕断丝连1.2 模块化思维导图1.3 模块解析1.3.1 KEY模块1.3.2 ADC模块1.3.3 IIC模块1.3.4 UART模块1.3.5 LCD模块1.3.6 LED模块1.3.7 TIM模块 2.源码3.第七届题目 前言&#xff1a;STM32G431RBT6实现嵌入式组第七届题目解析源码&…...

苹果iOS 18.4将强制升级HomeKit架构,旧版设备或无法使用

在科技飞速发展的当下,智能家居领域也在不断革新。而苹果公司作为科技行业的巨头,其每一次动作都备受关注。近日,有消息称苹果计划在iOS 18.4版本中停止对旧版HomeKit架构的支持,这一举措意味着用户将被迫升级,也可能对众多使用Apple Home应用的智能家居设备用户产生深远影…...

dit block部分

我首先会仔细阅读用户指令&#xff0c;明确用户的需求是基于文章的前十页内容&#xff0c;对3.2节“Diffusion Transformer Design Space”中的“DiT block design”部分进行原文翻译&#xff0c;并且在翻译完成后进行总结。为了完成这个任务&#xff0c;我需要先定位到文章的3…...

在MATLAB中实现PID控制仿真

在MATLAB中实现PID控制仿真可以通过代码编程或Simulink图形化建模两种方式完成。以下是两种方法的详细操作步骤和示例&#xff1a; 方法1&#xff1a;使用MATLAB脚本编程&#xff08;基于控制系统工具箱&#xff09; 步骤1&#xff1a;定义被控对象的数学模型 假设被控对象是…...

ChebyKAN0、ChebyKAN1 网络阅读

目录 ChebyKAN0 Chebyshev Polynomial-Based Kolmogorov-Arnold Networks: An Efficient Architecture for Nonlinear Function Approximation 参考文献 文章内容 文章详细结构 5. Experiments and Results 5.1 Digit Classification on MNIST 5.2 Function Approximat…...

Python核心模块的高级用法及Linux系统常用命令

一、Python相关 1、正则表达式 &#xff08;1&#xff09;正则表达式基础 ①含义&#xff1a;记录文本规则的代码。 ②注意&#xff1a;需要导入re模块 ③特点&#xff1a; 语法比较复杂&#xff0c;可读性较差。通用性很强&#xff0c;适用于多种编程语言 ④步骤&#…...

Spring 框架学习

技术体系结构 总体技术体系 单一架构 一个项目&#xff0c;一个工程&#xff0c;导出为一个 war 包&#xff0c;在一个 Tomcat 上运行&#xff0c;也叫 all in one。 单一架构&#xff0c;项目主要应用技术框架为&#xff1a;Spring、SpringMVC 、Mybatis。 分布式架构 一个…...

Python使用总结之深入理解 asyncio.Future——Python 异步编程的核心基石

深入理解 asyncio.Future&#xff1a;Python 异步编程的核心基石 在现代异步编程中&#xff0c;asyncio.Future 对象是 Python 异步生态系统的底层核心组件之一。它不仅是 Task 的基类&#xff0c;更是所有异步操作结果的统一抽象容器。本文将深入探讨它的设计哲学、运作机制和…...

ubuntu22.04 关于挂在设备为nfts文件格式无法创建软连接的问题

最近遇到情况&#xff0c;解压工程报错&#xff0c;无法创建软连接 但是盘内还有130G空间&#xff0c;明显不是空间问题&#xff0c;查找之后发现是移动硬盘的文件格式是NTFS&#xff0c;在ubuntu上不好兼容&#xff0c;于是报错。 开贴记录解决方案。 1.确定文件格式 使用命…...

pydub AudioSegment入门(基于Pyhton3)

目录 简介核心功能安装与依赖基本用法加载音频文件导出音频文件音频基础操作 简介 pydub 是一个简单易用的 Python 音频处理库&#xff0c;专注于提供高层次的音频操作接口&#xff0c;而 AudioSegment 是它的核心类&#xff0c;用于表示音频片段&#xff08;如 MP3、WAV、OGG…...

Python精进系列:filter 模块

Python filter 函数&#xff1a;数据筛选的利器 目录 Python filter 函数&#xff1a;数据筛选的利器引言一、filter 函数概述1.1 定义与基本语法1.2 返回值 二、简单示例&#xff1a;筛选偶数2.1 定义过滤函数2.2 使用 filter 函数进行筛选 三、使用 lambda 表达式简化代码3.1…...

LLM预训练过程-简明版本

文章总结自视频&#xff1a;【1080P】安德烈卡帕西&#xff1a;深入探索像ChatGPT这样的大语言模型&#xff5c;Andrej Karpathy_哔哩哔哩_bilibili 1. 准备训练集 详细的数据集准备方法可参考视频&#xff0c;或者huggingFace ​ 2. 分词&#xff08;Tokenizer&#xff09; …...

浅拷贝和深拷贝AI

值传递&#xff0c;在vue3中深拷贝的解决方法 1. 浅拷贝使用结构赋值使用 Object.assign 2. 深拷贝使用 JSON.parse(JSON.stringify())使用 Lodash 的 cloneDeep使用递归函数手动实现深拷贝 3. 使用 Vue 3 的响应式系统相关工具使用 toRaw使用 markRaw 4. 使用第三方库使用 str…...

mingw32编译ffmpeg

ffmpeg https://gitee.com/mirrors/ffmpeg.git 使用msys2的mingw32 pacman -S mingw-w64-x86_64-toolchain compile ./confiure --enable-static --disable-shared --enable-gpl --target-oswin32 mingw32-make -j4 提示编译错误&#xff0c;msys2里面的路径是/d/tools/msys2…...

MAVEN解决版本依赖冲突

文章目录 一、依赖冲突概念1、什么是依赖冲突2、依赖冲突的原因3、如何解决依赖冲突 二、查看依赖冲突-maven-helper1、安装2、helper使用1、conflicts的阅读顺序&#xff08;从下向上看&#xff09;2、dependencies as List的阅读顺序&#xff08;从下向上看&#xff09;3、de…...

地基注解@Controller和@RestController区别

前记&#xff1a;基础啊&#xff0c;区别点重点理解&#xff1b; 在Spring和Spring Boot框架中&#xff0c;Controller和RestController都用于处理HTTP请求&#xff0c;但它们在设计目的和用法上有显著区别。以下是它们的核心区别及示例说明&#xff1a; ​1. 核心区别 特性C…...

Linux Bash 单命令行解释 | 文件操作 / 字符串操作 / 重定向

注&#xff1a;本文为 “Linux Bash” 相关文章合辑。 中文引文&#xff0c;未整理。 英文引文&#xff0c;机翻未校。 第一部分&#xff1a;文件操作 1. 清空文件&#xff08;清除文件大小为 0&#xff09; $ > file这行命令使用输出重定向操作符 >。输出重定向造成文…...

【零基础入门unity游戏开发——进阶篇】Unity Microphone类处理麦克风相关信息,录制音频并实时处理或保存录制的音频数据

考虑到每个人基础可能不一样,且并不是所有人都有同时做2D、3D开发的需求,所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要讲解C#的基础语法,包括变量、数据类型、运算符、流程控制、面向对象等,适合没有编程基础的…...

在终端中用code命令打开vscode并加载当前目录了

注册code命令 启动 VSCode 编辑器,按 shift command p输入 shell command&#xff0c;选择 Install ‘code’ command in PATH 选项&#xff0c; 安装code 命令 此操作会把 code 命令添加到系统的环境变量里。 打开 iTerm2 终端 在 iTerm2 中&#xff0c;cd 代码库根目录, …...

无需 Docker 也能下载镜像!轻松获取 Docker 镜像文件!

背景问题 在日常开发或运维工作中&#xff0c;我们经常需要下载 Docker 镜像&#xff0c;但可能会遇到以下问题&#xff1a; &#x1f539; 服务器无法访问 Docker Hub&#xff0c;导致 docker pull 失败。 &#x1f539; Windows 端没有安装 Docker&#xff0c;但仍然需要获…...

ESMFold对决AlphaFold:蛋白质-肽相互作用预测的新进展

今天向大家介绍的这篇文章题目为&#xff1a;“Protein−Peptide Docking with ESMFold Language Model”&#xff0c;近期发表在JCTC上。 本文主要研究 ESMFold 语言模型在蛋白质-肽对接中的应用。通过探索多种对接策略&#xff0c;评估其在预测蛋白质-肽相互作用方面的性能&a…...

win终端添加git-bash,支持linux的shell语法

git的git-bash支持很多linux的语法&#xff0c;比如ll&#xff0c;rm等等&#xff0c;用着很方便&#xff0c;比cmd、ps用着习惯 点击下箭头&#xff0c;设置 添加新配置 配置 地址为git地址\bin\bash.exe&#xff0c;不要用根目录的git-bash.exe&#xff0c;这个会打开新弹窗后…...

wpf中DataGrid组件每一行的背景色动态变化

背景描述&#xff1a;存在多个轧辊&#xff0c;其中有的轧辊是成对的&#xff0c;成对的辊ROLL_NO这个变量的值相同&#xff0c;有的轧辊是单个暂时没有配对的。成对的辊北京颜色交替突出显示&#xff0c;单个辊不需要设置背景色。 实现&#xff1a; 换辊的时候给成对的辊分配相…...

002-告别乱码-libiconv-C++开源库108杰

本课文包含三个视频&#xff01; 为什么中文版Windows是编程出现乱码的高发地带&#xff1f;怎么用 libiconv 把国标编码的汉字转换成宇宙统一码&#xff1f;怎么简化 libiconv 那些充满坑的 纯C 函数API&#xff1f; 1. 安装 libiconv 通常&#xff0c;你在 MSYS2 中安装过 G…...

DeepSeek赋能智慧交通:城市交通流量智能预测与优化,开启智能出行新时代

在数字化转型的浪潮中&#xff0c;智慧交通正成为提升城市运行效率、改善居民出行体验的关键领域。 DeepSeek作为人工智能领域的前沿技术&#xff0c;凭借其强大的数据分析、智能决策和多模态交互能力&#xff0c;正在为智慧交通注入新的活力&#xff0c;推动交通管理从“经验…...

Token登录授权、续期和主动终止的方案(Redis+Token(非jwtToken))

1、RedisToken方案的授权 1.1 基本原理 登录后使用UUID生成token&#xff0c;前端每次请求都会带上这个token作为授权凭证。这种方案是能自动续签&#xff0c;也能做到主动终止。所以很多项目用的都是RedisToken方案&#xff0c;简单方便问题少。缺点就是需要依赖Redis和数据…...