Java中的序列化

【java】java序列化、ArrayList序列化、序列化策略 1、如果一个类想被序列化,需要实现Serializable接口。否则将抛出异常,这是因为,在序列化操作过程中会对类型进行检查,要求被序列化的类必须属于Enum、Array和Serializable类型其中的任何一种。2、在变量声明前加上该关键字,可以阻止该变量被序列化到文件中。3、在类中增加writeObject 和 readObject 方法可以实现自定义序列化策略。 阅读详情

主要谈一谈Java中的序列化问题,包括Serializable与Externalizable介绍以及一些项目中的用法。

1、序列化是什么意思?用来干嘛的

      序列化:将对象的状态信息转换为可以存储或传输的形式的过程。不过存储倒是很少见,工作中大多都是传输。比如远程
方法调用就是用到的特别多。差不多就相当于科幻片中的那种将固体液化,顺着水管流到某个地方然后在固化。那么液化的过
程就是类似于序列化,固化的过程就是反序列化。
      通常开发人员只需要了解被序列化的类需要实现 Serializable 接口,使用 ObjectInputStream 和 ObjectOutputStream 进行
对象的读写。然而在有些情况下,光知道这些还远远不够。因为,你的眼界决定了项目的高度!

2、Java中提供的默认序列化Serializable

我们先写一个User类,然后主要通过代码说明下。User类的主要结构如下,主要就三个字段,id,name,passwd
package com.ztesoft.ser;

public class User {
	private int id;
	
	private String name;

	private String passwd;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPasswd() {
		return passwd;
	}

	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
	
}
接着我们写个测试类,将这个对象序列化到磁盘中
@Test
public void serializWrite(){
	User user = new User(1, "dgh", "123456");
		
	File file = new File("D:/user.info");
	ObjectOutputStream oos = null;
	try {
		oos = new ObjectOutputStream(new FileOutputStream(file));
			
		oos.writeObject(user);
			
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		IOUtils.closeQuietly(oos);
	}
}
接着就报了一个异常:java.io.NotSerializableException: com.ztesoft.ser.User
所以我们得到第一个结论:如果使用默认的序列化,则需要序列化的对象就需要直接或者间接的实现Serializable接口。
现在我们给User类添加接口实现,然后在调用方法,则正常运行。User这个对象被序列化到硬盘上了。但是有个警告:

下面就主要说说这个序列化ID。
2.1、序列化ID的问题 serialVersionUID
      有一个异常叫做:java.io.InvalidClassException:  stream classdesc serialVersionUID = 5835067920559730690, 
local class serialVersionUID = 583506792055970690这个异常发生在反序列化的时候,为什么有这个异常呢?
      因为:虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是
否一致(就是 private static final long serialVersionUID = 1L)。由于序列化 ID 不同,他们无法相互序列化和反序列化。也
就导致了上面类似的异常抛出。
      序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上
是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序
列化成功。那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。比如:
修改了服务端类的序列化id之后,只有与服务端保持一致序列化id的那些客户端才能调用。不过一般没有人这么做。
2.2、静态变量的序列化
第一步:我们修改User,添加一个成员变量。就叫做state吧,static修饰的哦。

第二步:写一个测试类,先序列化到硬盘,在反序列化到回来但是发现了一个严重问题:

      这是为什么呢?对于无法理解的读者认为,state 是从读取的对象里获得的,应该是保存时的状态才对啊,我保存的时
候是error那么序列化回来应该也是error,为什么就成了ok了呢?之所以变成ok的原因在于序列化时,并不保存静态变量,
这其实比较容易理解,序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量。
2.3、父类序列化与transient关键字
我们先说一下transient关键字,我们在passwd字段前面加上这个关键字修饰,然后在反序列化回来

      很神奇吧,passwd应该是123456的,但是这里却没有了。其实transient这个关键字的作用就是使字段不被序列化。
我们熟悉使用 Transient 关键字可以使得字段不被序列化,那么还有别的方法吗?根据父类对象序列化的规则,我们可以
将不需要被序列化的字段抽取出来放到父类中,子类实现 Serializable 接口,父类不实现,根据父类序列化规则,父类的
字段数据将不被序列化。所以父类序列化的代码就不演示了。
2.4、对敏感字段的加密
      我们可不可以有什么办法自定义序列化的方式呢?比如序列化时给字段加密,这样别人也不容易破解了。其实是有的:
在序列化过程中,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化。
      如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 
defaultReadObject 方法。用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在
序列化的过程中动态改变序列化的数值。基于这个原理,可以在实际应用中得到使用,用于敏感字段的加密工作。
修改User代码,添加两个方法:writeObject 和readObject
private void writeObject(ObjectOutputStream out) {
	try {
		// 这里可以加密
		out.writeObject(passwd);
	} catch (IOException e) {
		e.printStackTrace();
	}
}

private void readObject(ObjectInputStream in) {
	try {
		// 这里就可以解密了
		passwd = (String) in.readObject();
	} catch (Exception e) {
		e.printStackTrace();
	}
}
之后我们调用测试方法,发现结果是:
      state因为是静态的,有值是正常的,id与name因为我们自定义的方法中么有处理,因此就没有值。也就是说如果我们写了
writeObject与readObject,那么序列化与反序列话就会使用我们自定义的方法。
      RMI 技术是完全基于 Java 序列化技术的,服务器端接口调用所需要的参数对象来至于客户端,它们通过网络相互传输。这就
涉及 RMI 的安全传输的问题。一些敏感的字段,如用户名密码(用户登录时需要对密码进行传输),我们希望对其进行加密,
这时,就可以采用本节介绍的方法在客户端对密码进行加密,服务器端进行解密,确保数据传输的安全性。
2.6、单例模式与序列化
第一步:首先写一个单例类
package com.ztesoft.ser;

public class Singleton implements java.io.Serializable {
	/** */
	private static final long serialVersionUID = 780762366800963430L;

	public static Singleton INSTANCE = new Singleton();

	// 私有构造器
	private Singleton() { }
}
第二步:写个测试方法,测试一下看看结果
public void singletonTest(){
	Singleton s1 = Singleton.INSTANCE;
		
	File file = new File("D:/singleton.info");
	ObjectOutputStream oos = null;
	ObjectInputStream ois = null;
	try {
		// 序列化对象到硬盘
		oos = new ObjectOutputStream(new FileOutputStream(file));
		oos.writeObject(s1);
			
		// 反序列化
		byte[] bytes = IOUtils.toByteArray(new FileInputStream(file));
	        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
	        Singleton s2 = (Singleton) in.readObject();
	        
		System.out.println(s1 == s2);
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		IOUtils.closeQuietly(oos);
		IOUtils.closeQuietly(ois);
	}
}
第三步:发现控制台输出的是false,也就是说单例类被破坏了。
为了避免这中情况,我们需要在需要序列化的类中添加一个方法 readResolve:
这个时候在跑一下测试代码,看看是否有问题

3、Externalizable接口的使用

jdk还给我们提供了另外一种自定义序列化的借口。那就是Externalizable啦,首先我们看看源码:
public interface Externalizable extends java.io.Serializable {
	
    void writeExternal(ObjectOutput out) throws IOException;
    
    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

      这个接口继承了Serializable接口,并有两个方法,一个write一个read。其实和我们的readObject与writeObject一样的啦。
个人觉得只是更方便了而已,有兴趣可以研究下他们之间的差别。我是没研究。

4、题外话

      java虽然提供了很好的序列化,但是序列化之后的文件还是比较大的。目前很多开源的项目为了提高效率都使用更好的
替代方法,比如protobuf等。以后有机会在介绍这个东西吧。
Java 中的​​序列化与​​反序列化 若需要控制序列化/反序列化的细节(如加密、压缩),可通过重写和方法实现。若需要对敏感字段(如密码)进行加密存储,可通过重写和readObject方法自定义序列化过程。​​定义SecureUser类(自定义序列化)​​:java复制// 敏感字段,不直接序列化// AES 密钥(16字节)// 自定义序列化逻辑(加密密码)// 默认序列化非 transient 字段(username)try {// 加密密码// 写入加密后的密码。 阅读详情

相关推荐

保姆级教程:用Comsol Multiphysics仿真你的第一个SAW滤波器(含压电材料参数设置)

本文提供了一份详细的COMSOL Multiphysics教程,指导读者完成表面声波滤波器(SAW)的压电仿真全流程。从压电材料参数设置、叉指换能器建模到多物理场耦合分析,特别强调了实际应用中容易出错的细节和解决方案,帮助工程师快速掌握SAW滤波器仿真技术。

weixin_42665255的博客 592

流的关闭操作IOUtils.closeQuietly()已过时

IOUtils.closeQuietly()本来简化了流的关闭操作,随着版本更迭,IDEA中已经没有了.closeQuietly() IOUtils包由org.apache.io变成org.apache.commons.compress.utils.IOUtils 以url方式访问hdfs为例: public void demo1()throws Exception{ //注册hdfs 的url URL.setURLStreamHandlerFac.

weixin_47878012的博客 6451

攻防世界:Crypto习题之easy_RSA

在非对称加密算法中,单向函数被广泛应用,用于确保从公钥加密后的密文无法轻易推导出私钥,从而保证数据的安全性。而其中最著名的算法便是 RSA 加密算法。首先设φm:=∣1≤k≤mgcdkm1∣为欧拉函数(Euler’sche Phi-function)。pqn:=pqpqφnnpqpqφnp−1q−1e∈12...φn−1gcdφne1ended≡1φn假设我们现在有明文x以及公钥en。

qq_52789488的博客 1573

IOUtils.closeQuietly:在finally中关闭流时不需要再catch一遍IOException

在使用 stream 的时,往往要 try catch IOException。eric教导我要把流的关闭放到 finally 中去写,并且在 close 之前要判断一下是否为 null。但是 stream.close() 也会 throw IOException,这就导致在 finally 中 也需要 try catch 一下,于是代码就很长。如下: byte[] data = new b...

淡然坊 2万+

数理金融学笔记 Chap2 二叉树模型Binomial

2 二叉树模型与期权定价 Binomial Model and Option Pricing 文章目录2 二叉树模型与期权定价 Binomial Model and Option Pricing单期二叉树模型 One-step Binomial Model风险与无风险资产单期二叉树模型与无套利条件无套利定价 No Arbitrage Pricing风险中性定价 Risk Neutral PricingDelta套期保值 Delta Hedging两期二叉树模型 Two-Step Binomial Model

weixin_66831131的博客 2389

SAP FICO CK40N批量发布标准价:常见报错排查与实战解决指南

本文详细解析了SAP FICO模块中CK40N批量发布标准价的常见报错及解决方案。从物料选择、成本核算到最终发布的全流程,提供了针对'已有标准成本估算记号'等典型报错的实战处理技巧,并分享了预防性维护与批量处理的高效方法,帮助财务人员提升工作效率。

weixin_29234509的博客 306

IOUtils.closeQuietly();

@RequestMapping("/getoplogphotoimg") @ResponseBody public String getoplogphotoimg(HttpServletRequest request, HttpServletResponse response) throws Exception{ String photoId = request.getParameter("...

兴趣是最好的老师 5351

【stm32+K210项目】基于K210与STM32协同工作的智能垃圾分类系统设计与实现(完整工程资料源码)

本系统采用SG90舵机Maix Bit摄像头STM32C8T6主控板以及LX_TRIG_MP3_V6.0语音播报模块,构建了一套高效的智能垃圾分类系统,综合运用了图像识别、语音播报及精准控制技术。SG90舵机负责控制垃圾桶的开盖操作。该舵机通过接收PWM信号来实现转动,内部有一个基准电路产生周期为20ms的PWM信号,通过外部脉冲信号的控制(高电平时间在0.5ms至2.5ms之间),使得舵机的输出轴转动到指定位置。舵机内的位置反馈电位计。

嵌入式技术开发 5100

java常用的8个开源类库

8个开源类为:IOUtils、FileUtils、StringUtils、FilenameUtils、ArrayUtils、DigestUtils、StringEscapeUtils、BeanUtils 连接地址:https://blog.csdn.net/qing_gee/article/details/104387940 昨天在青铜时代群里看到读者朋友们在讨论 Java 最...

beidaol的专栏 952

Docker 环境 Playwright MCP 部署全流程指南

Docker部署Playwright MCP全流程指南 本文详细介绍了使用Docker容器化部署Playwright MCP的完整流程,涵盖镜像拉取、容器启动、配置优化和问题排查。主要内容包括: 核心部署步骤:通过官方镜像快速搭建环境,支持自定义端口和数据持久化 关键配置要点:详解网络设置、持久化目录挂载和环境变量配置 服务验证方法:通过日志检查和服务连通性测试确保部署成功 客户端集成:提供VS Code等IDE的配置示例 常见问题解决:针对浏览器启动超时、跨域限制等问题给出解决方案 实战案例:演示自动化爬

勤奋的码农 1474

【机器学习-09】特征工程

特征工程是机器学习模型构建的初步工作,但它的重要性却贯穿整个模型生命周期。在进行特征工程时,我们需要充分利用数据科学的知识和技巧,结合具体的应用场景和业务需求,来制定出最合适的特征提取和转换策略。只有这样,我们才能为机器学习模型提供最有价值的输入,从而使其发挥出最大的潜力。总之,特征工程是机器学习中的一项关键任务,它需要我们用心去探索、去实践、去创新。只有不断地优化和完善特征工程的过程,我们才能构建出更加准确、更加可靠的机器学习模型,为实际应用带来更大的价值。

qq_38614074的博客 2万+

Java中的序列化到底是什么

我们都知道,新建一个对象的时候实现 Serializeable 接口,但为什么要这么做?什么时候这样子做?这样子做会不会出现幺蛾子?阿淼一个三连差点把自己都问懵逼了…… 那接下来,大家就和阿淼一起简单了解一下这个知识点吧…… 序 序列化的定义是:将一个对象编码成一个字节流(I/O);而与之相反的操作被称为反序列化。 序列化的目的是为了方便数据的传递以及存储到磁盘上(把一个Java对象写入到硬盘或者传输到网路上面的其它计算机,这时我们就需要将对象转换成字节流才能进行网络传输。对于这种通用的操作,就出现了序列化

Java学习之道 1万+

Windows10下安装VMware16虚拟机

由于本人系统为Windows 10 家庭中文版,无法安装Linux子系统WSL,虽然网上也有强制安装的方法,但为保险起见,还是把之前的VMware虚拟机重新进行安装,并浅浅记录一下安装过程。

沉香best的博客 865

Java中的序列化及序列化ID

参考转载自: 秒懂Java序列化与反序列化 Java的序列化ID的作用 1. 定义 Java的序列化:是指把Java对象转换为字节序列的过程 Java的反序列化:是指把字节序列恢复为Java对象的过程 2. 为什么需要 我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,.

三明治文鱼的博客 5841

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Java序列化与反序列化

Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨。  1.Java序列化与反序列化  Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。  2.为什么需要序列化与反序列化  我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频

数据人 24万+

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

详解JAVA序列化

进来,一文给你讲明白“序列化”。

BugMan的博客 9396

JAVA的序列化

Java序列化其实这个用的多不多,我觉得看公司的技术栈吧,如果用的是cloud那套,估计接触的会少点,但是也不是说没有,如果是dubbo那套的话,就多点,上次我们说Netty的编码解码的时候说到了谷歌的protoBuf,今天的话我们就来好好看看Java序列化,详细的聊聊从上面这张图我们可以看到,两个进程进行通信时候,想要发送数据,要先要把数据发送到TCP缓冲区,然后形成报文再发送出去,同样的道理,接收端也是一样。我们可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式

m0_71563599的博客 1万+

java中的序列化

重写writeObject和readObject方法:在类中自定义`writeObject`和`readObject`方法,优化序列化和反序列化过程。- Externalizable接口:实现`Externalizable`接口,自定义`writeExternal`和`readExternal`方法,完全控制序列化和反序列化过程。

weixin_44711513的博客 1664

【潜意识Java】Java中的序列化与反序列化

朋友,在 Java 开发里,序列化与反序列化可是相当重要的概念。想象一下,你要把一个复杂的 Java 对象从一台机器传输到另一台机器,或者把它存储到磁盘里,这时候该咋办呢?序列化和反序列化就派上大用场啦。我在项目里处理数据传输和存储的时候,没少和它们打交道,现在就把我的经验分享给你。

潜意识Java的博客 1045

java序列化中的常量_Java 序列化

对象序列化的目标是将对象保存在磁盘中或者在网络中进行传输。实现的机制是允许将对象转为与平台无关的二进制流。java中对象的序列化机制是将允许对象转为字节序列。这些字节序列可以使Java对象脱离程序存在,从而可以保存在磁盘上,也可以在网络间传输。对象的序列化是将一个Java对象写入IO流;与此对应的,反序列化则是从IO流中恢复一个Java对象。要将一个java对象序列化,那么对象的类需要实现Seri...

weixin_28703489的博客 631

什么是Java的序列化?

Java的序列化一、序列化的含义、意义及使用场景二、序列化实现的方式2.1 Serializable(1)普通序列化(2)成员是引用的序列化(3)同一对象序列化多次的机制(4)java序列化算法潜在的问题(5)可选的自定义序列化2.2 Externalizable:强制自定义序列化2.3 两种序列化机制对比三、序列化版本号serialVersionUID四、总结 一、序列化的含义、意义及使用场景 序列化:将对象写入到IO流中 反序列化:从IO流中恢复对象 意义:序列化机制允许将实现序列化的Java对象转换位

weixin_43520450的博客 2852

Java 序列化

如果我们需要持久化Java对象比如说将Java对象保存在文件中,或者在网络传输Java对象,这些场景都需要序列化。简单来说序列化:将数据结构或者对象转换成可以存储或传输的形式,通常是二进制字节流,也可以是JSON,XML等文本格式反序列化:将在序列化过程中所生成的数据转换为原始数据结构或者对象的过程。

rc1596919047的博客 986

java序列化指的是什么,java的序列化是什么

序列化:指堆内存中的java对象数据,通过某种方式把对存储到磁盘文件中,或者传递给其他网络节点(网络传输)。这个过程称为序列化,通常是指将数据结构或对象转化成二进制的过程。 (推荐学习:java课程)即将对象转化为二进制,用于保存,或者网络传输。序列化的作用① 想把内存中的对象保存到一个文件中或者数据库中时候;② 想用套接字在网络上传送对象的时候;③ 想通过RMI传输...

weixin_39820226的博客 2019

java的序列化号_java中的序列化

一、什么是java序列化序列化:将对象写入IO流反序列化:从IO流中恢复对象序列化机制允许将实现序列化的java对象转换为字节序列,这些字节序列可以保存在磁盘上也可以通过网络传输,字节序列也可以再恢复为原来的对象。序列化机制可以让对象不依附于程序独立存在。二、应用场景所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回...

weixin_32591455的博客 546
上一篇: 【WebService】第六章、Axis1.4发布的webservice如何调用
下一篇: No space left on device
Readiay
博客等级 码龄14年 166粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值