一文了解Java序列化与反序列化

article/2025/9/14 2:46:12

目录

  • 序列化示例
  • 有父类的对象序列化
  • Serializable和Externalizable区别
  • 序列化和反序列化实现
  • serialVersionUID不一致有什么问题
    • 1、先注释掉反序列化代码, 执行序列化代码, 然后User类新增一个属性sex
    • 2、再注释掉序列化代码执行反序列化代码
    • 3、指定serialVersionUID
  • 序列化字段修饰
  • static属性为什么不会被序列化?
  • serialVersionUID也被static修饰, 为什么serialVersionUID会被序列化?
  • 小结

在这里插入图片描述
相关阅读:
什么是序列化

序列化示例

String类型序列化的源码示例:

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];/** Cache the hash code for the string */private int hash; // Default to 0/** use serialVersionUID from JDK 1.0.2 for interoperability */private static final long serialVersionUID = -6849794470754667710L;private static final ObjectStreamField[] serialPersistentFields =new ObjectStreamField[0];public String() {this.value = "".value;}
...
}

String类型实现了Serializable接口, 并显示指定serialVersionUID的值.

对象持久化到数据库示例:

<insert id="insertUser" parameterType="xxx.User">  INSERT INTO user(name, age) VALUES (#{name}, #{age})  
</insert>  

实际上我们并不是将整个对象持久化到数据库中, 而是将对象中的属性持久化到数据库中, 而这些属性都是实现了Serializable接口的基本属性。

有父类的对象序列化

在Java中,如果对象的类或父类实现了Serializable接口或Externalizable接口,则称该对象可序列化。

有继承的对象序列化有如下三种情况:

  1. 如果父类可序列化,则子类可自动序列化
  2. 即使父类不可序列化,子类仍可以序列化
  3. 如果我们希望子类不被序列化,即使父类是可序列化的

类可序列化时,子类自动变为可序列化示例:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;class Parent implements Serializable {String name = "三省同学";
}class Child extends Parent {String name1 = "sxtx";
}/*** 父类序列化,子类自动序列化示例** @Author sxtx*/
public class SerializableExample {public static void main(String[] args) throws IOException, ClassNotFoundException {Child writer = new Child();FileOutputStream fos = new FileOutputStream("file.txt");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(writer);FileInputStream fis = new FileInputStream("file.txt");ObjectInputStream ois = new ObjectInputStream(fis);Child reader = (Child) ois.readObject();System.out.println(reader.name + "," + reader.name1);}
}

输出:

三省同学,sxtx

Serializable和Externalizable区别

1、Serializable序列化时不会调用默认的构造器,而Externalizable序列化时会调用默认构造器的。
2、Serializable:一个对象想要被序列化,那么它的类就要实现此接口,这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。
3、Externalizable:他是Serializable接口的子类,有时我们不希望序列化那么多,可以使用这个接口,这个接口的writeExternal()和readExternal()方法可以指定序列化哪些属性。

序列化和反序列化实现

三种实现方式如下:

1、若User类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化。

ObjectOutputStream采用默认的序列化方式,对User对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对User对象的非transient的实例变量进行反序列化。

2、若User类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。

ObjectOutputStream调用User对象的writeObject(ObjectOutputStream out)的方法进行序列化。

ObjectInputStream会调用User对象的readObject(ObjectInputStream in)的方法进行反序列化。

3、若User类实现了Externalnalizable接口,且User类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。

ObjectOutputStream调用User对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用User对象的readExternal(ObjectInput in)的方法进行反序列化。

代码示例:

@Data
public class User implements Serializable {private String name;  private Integer age;@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}

先进行序列化, 再进行反序列化.

 public static void main(String[] args) throws Exception {User user = new User();  user.setName("三省同学");user.setAge(18);  System.out.println("序列化前的结果: " + user);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\file.txt")));oos.writeObject(user);oos.close();ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\file.txt")));User dUser = (User) ois.readObject();System.out.println("反序列化后的结果: "+ dUser);}  

结果:

序列化前的结果: User{name='三省同学', age=18}
反序列化后的结果: User{name='三省同学', age=18}

serialVersionUID不一致有什么问题

1、先注释掉反序列化代码, 执行序列化代码, 然后User类新增一个属性sex

@Data
public class User implements Serializable {private String name;  private Integer age;private String sex;@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}
}

2、再注释掉序列化代码执行反序列化代码

最后结果如下:


序列化前的结果: User{name='三省同学', age=18}Exception in thread "main" java.io.InvalidClassException: xxx.User; local class incompatible: stream classdesc serialVersionUID = -5701321611009304438, local class serialVersionUID = 1670957499376994577at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)at xxx.SerializableTest.main(SerializableTest.java:18)

报错结果为序列化与反序列化产生的serialVersionUID不一致.

3、指定serialVersionUID

private static final long serialVersionUID = 1L;  

再执行上述步骤, 结果如下:

序列化前的结果: User{name='tyshawn', age=18} 
反序列化后的结果: User{name='tyshawn', age=18, sex='null'}

指定serialVersionUID可解决了序列化与反序列化产生的serialVersionUID不一致的问题.

序列化字段修饰

被transient关键字修饰的属性不会被序列化, static属性也不会被序列化.

static属性为什么不会被序列化?

因为序列化是针对对象而言的, 而static属性优先于对象存在, 随着类的加载而加载, 所以不会被序列化.

serialVersionUID也被static修饰, 为什么serialVersionUID会被序列化?

其实serialVersionUID属性并没有被序列化, JVM在序列化对象时会自动生成一个serialVersionUID, 然后将我们显示指定的serialVersionUID属性值赋给自动生成的serialVersionUID.

小结

1、序列化时,只对对象的状态进行保存,而不管对象的方法;
2、当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
3、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
4、并非所有的对象都可以序列化,比如:

安全方面的原因:
如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;

资源分配方面的原因:
比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;

5、声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。

6、序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。为它赋予明确的值。显式地定义serialVersionUID有两种用途:

在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

7、Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的;

8、如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存!这是能用序列化解决深拷贝的重要原因;

在这里插入图片描述

点赞 收藏 关注
三月春花渐次醒,迢迢年华谁老去


http://chatgpt.dhexx.cn/article/o2xNwZQ6.shtml

相关文章

一篇搞懂java序列化Serializable

序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。 一、序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化。 把字节序列恢复为对象的过程称为对象的反序列化。 对象的序列化主要有两种用途&#xff1a; 1&#xff09; 把对象…

Java序列化与数据传输

1&#xff09;什么是序列化 ① 序列化&#xff1a;Java 提供了一种对象序列化的机制&#xff0c;该机制中&#xff0c;一个对象可以被表示为一个字节序列&#xff0c;该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。 堆内存中的java对象数据&…

java序列化的作用

1.java序列化需要实现Serializaible接口或者Externalizable接口 2.java实现序列化的作用: 1.方便在远程调用时对象的解码与编码,就像new对象之间直接调用&#xff0c;不需要像传输对象之间像JSON转换一样转来转去 2.序列化的能力&#xff1a;为了在程序中能直接以对象的形式进…

Java序列化与反序列化

参考链接&#xff1a; Java 序列化与反序列化_Jacks丶的博客-CSDN博客_java反序列化 1 序列化与反序列化的概念 Java 序列化是指&#xff1a;将对象转化成一个字节序列(二进制数据)的过程。 将序列化对象写入文件之后&#xff0c;可以从文件中读取出来&#xff0c;并且对它…

Java序列化

一、什么是序列化&#xff1f;为什么要序列化&#xff1f; Java 序列化就是指将对象转换为字节序列的过程&#xff0c;而反序列化则是只将字节序列转换成目标对象的过程。 我们都知道&#xff0c;在进行浏览器访问的时候&#xff0c;我们看到的文本、图片、音频、视频等都是通…

【JAVA基础】java基础之-序列化详解

写在前面的话 脑子是个好东西&#xff0c;可惜的是一直没有搞懂脑子的内存删除机制是什么&#xff0c;所以啊&#xff0c;入行多年&#xff0c;零零散散的文章看了无数&#xff0c;却总是学习了很多也忘了很多。 痛定思痛的我决定从今天开始系统的梳理下知识架构&#xff0c;记…

JAVA的序列化

絮叨 Java序列化其实这个用的多不多&#xff0c;我觉得看公司的技术栈吧&#xff0c;如果用的是cloud那套&#xff0c;估计接触的会少点&#xff0c;但是也不是说没有&#xff0c;如果是dubbo那套的话&#xff0c;就多点&#xff0c;上次我们说Netty的编码解码的时候说到了谷歌…

MySQL卸载重新安装会遇到的问题及解决方式

好家伙&#xff0c;全踩雷了&#xff1a; 一.使用cd命令无法进入到其他盘符&#xff1f; 解决&#xff1a;在cd后加/d&#xff0c;两者之间用空格隔开 二.初始化时没有给出密码&#xff1f; 解决&#xff1a;仔细检查my.ini配置文件中的配置命令&#xff0c;一般是配置命令写错…

如何将MySQL卸载干净?

前言 前几天不知道什么情况电脑被莫名下载了MySQL8.0版本导致与本机的MySQL5.0版本冲突&#xff0c;导致MySQL无法正常运行&#xff0c;后来因为没有卸载干净MySQL导致一直下载不成功&#xff0c;导致我晚上失眠&#xff0c;现在让我们进入正题&#xff0c;看看如何将他卸载干…

【通关MySQL】Win11如何将MySQL卸载干净?

✨哈喽&#xff0c;进来的小伙伴们&#xff0c;你们好耶&#xff01;✨ &#x1f680;&#x1f680;系列专栏:【通关MySQL】 ✈️✈️本篇内容: MySQL如何卸载干净&#xff1f; ⛵⛵作者简介&#xff1a;一名双非本科大三在读的科班Java编程小白&#xff0c;道阻且长&#xff…

如何能将mysql卸载干净

本篇文章介绍一下如何干净卸载mysql。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对大家有所帮助。 第七步出现找不到相应的文件夹。第七步&#xff1a;路径是C:\Users\你的用户名字\AppData\Roaming\MySQL 有可能是隐藏的&#xff0c;需要显示隐藏…

如何将mysql卸载干净

一、在控制面板中卸载mysql软件 二、卸载过后删除C:\Program Files (x86)\MySQL该目录下剩余了所有文件&#xff0c;把mysql文件夹也删了 三、windowsR运行“regedit”文件&#xff0c;打开注册表 四、删除注册表&#xff1a;HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Service…

MySQL卸载安装

目录 MySQL卸载安装 1. MySQL卸载&#xff08;8.0版本&#xff09; 1.1停止MySQL服务 1.2 卸载MySQL相关组件 1.3删除MySQL安装目录 1.4删除MySQL数据目录 1.5 删除MySQL注册表信息&#xff08;重要&#xff09; 2. MySQL安装&#xff08;5.7.24版本&#xff09; 2.1安装…

mysql卸载不_mysql卸载不干净解决方法

一、在控制面板中卸载mysql软件&#xff0c;此时mysql没有卸载干净。 二、卸载过后删除C:Program Files (x86)MySQL该目录下剩余了所有文件&#xff0c;把mysql文件夹也删了 三、windowsR运行“regedit”文件&#xff0c;打开注册表 四、删除注册表&#xff1a;HKEY_LOCAL_MACH…

MySQL的卸载与安装(附管理工具Navicat SQLyog)

本文MySQL为5.1.51版本&#xff0c;附全文所需文件压缩包&#xff08;百度云 提取码&#xff1a;8778&#xff09;&#xff0c;其中SQLyog和Navicat为MySQL的图形化工具&#xff0c;任选其一安装即可&#xff08;建议Navicat&#xff09; 1.MySQL卸载 如果之前没有安装过MySQ…

【 Windows、Mac 】Mysql 卸载、安装

文章目录 Windows Mysql 卸载、安装一、彻底卸载mysql二、安装mysql 5.7三、安装 mysql 8四、MySql服务开机自启动失败 Mac 安装 mysql一、下载对应mysql版本二、安装三、重置密码 Windows Mysql 卸载、安装 一、彻底卸载mysql 1、关闭 MySql 服务。 2、在控制面板卸载mysq…

MySQL卸载、安装与使用

一、MySQL卸载 1.关闭服务 点击win&#xff0c;输入服务&#xff0c;找到MySQL的服务&#xff0c;右击停止该服务 2.删除服务 点击win&#xff0c;输入cmd&#xff0c;选择管理员身份运行。打开cmd&#xff0c;输入sc delete mysql 3删除配置的MySQL环境变量 MySQLHOME和…

MySQL卸载不干净问题

解决MySQL卸载不干净或安装的时候安装不成功&#xff0c;输入密码一直检查不通过问题 MySQL卸载不干净&#xff0c;之后安装就会遇到很多问题&#xff0c;我也遇到了这种情况&#xff0c;裝了好久&#xff0c;一到这里就会有问题&#xff0c;尝试卸载了很多次然后在从新裝&…

mysql卸载详细教程

完整卸载MySQL数据库 1、关掉mysql服务 直接搜索服务或者右键“我的电脑”&#xff0c;选择“管理”&#xff0c;打开计算机管理&#xff0c;选择“服务”右键MySQL服务&#xff0c;选择“停止” 2、 卸载mysql程序 开始菜单->控制面板->程序和功能 3、 删除计算机上…

免装版mysql卸载

免装版mysql卸载: 1.停止mysql服务:以管理员身份打开cmd执行:net stop mysql 2.删除Mysql的注册表 winr 输入regedit打开注册表: 3.管理员cmd执行:mysqld -remove mysql 4.删除mysql之前的安装包: