第十三章 序列化与反序列化

文章目录

  • 第十三章 序列化与反序列化
  • 一、概念
    • 1.序列化与反序列化
    • 2.序列化有什么作用
  • 二、代码实现
    • 1.思路
    • 2.创建一个Student类
    • 3.创建TestSerializable测试类
  • 三、SerialVersionUID
    • 1.概念
    • 2.自定义serialVersinUID

一、概念

1.序列化与反序列化

Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象
整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象
类 ObjectInputStream 和 ObjectOutputStream 是高层次的数据流,它们包含反序列化和序列化对象的方法

  • 序列化:把对象转换为字节序列的过程称为对象的序列化
  • 反序列化:把字节序列恢复为对象的过程称为对象的反序列化

简而言之:序列化的作用就是为了不同 JVM 之间共享实例对象的一种解决方案

2.序列化有什么作用

  1. 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中
  2. 在网络上传送对象的字节序列

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是 Web 服务器中的 Session 对象,当有 10 万用户并发访问,就有可能出现 10 万个 Session 对象,内存可能吃不消,于是 Web 容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送。接收方则需要把字节序列再恢复为Java对象

二、代码实现

1.思路

序列化:

  1. 准备要序列化的对象和序列化的目标文件路径
  2. 序列化对象所在的类必须实现 Serializable 接口
  3. 创建序列化流对象 ObjectOutputStream out = new ObjectOutputStream(new FileInputStream(File/路径))
  4. 进行对象的序列化输出 out.writeObject(s)
  5. 关流 out.close()

反序列化:

  1. 前提:有序列化的数据才能通过反序列化恢复成对象
  2. 序列化版本号必须一致,最好一次序列化对应一次反序列化
  3. 创建反序列化流对象 ObjectInputStream in = new ObjectInputStream(new FileInputStream(File/路径))
  4. 恢复对象 Object o = in.readObject()
  5. 关流 in.close()

2.创建一个Student类

package com.sisyphus.serializable;import java.io.Serializable;/*@Description: 本类用于封装学生类$* @Param: $* @return: $* @Author: Sisyphus* @Date: 7/17$
*//*** 如果本类想要完成序列化,必须实现可序列化接口,否则会报错* 报错信息:* NotSerializableException:com.sisyphus.serializable.Student* Serializable 接口是一个空接口(标记接口)* 作用是用来当作标记,标记这个类的对象可以被序列化输出*/
public class Student implements Serializable {//private static final long serialVersionUID = 1L;//1.1定义学生的相关属性并封装private String name;//姓名private int age;//年龄private String addr;//住址private char gender;//性别public Student() {System.out.println("无参构造");}public Student(String name, int age, String addr, char gender) {System.out.println("全参构造");this.name = name;this.age = age;this.addr = addr;this.gender = gender;}//1.2提供对应的所有方法public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getAddr() {return addr;}public void setAddr(String addr) {this.addr = addr;}public char getGender() {return gender;}public void setGender(char gender) {this.gender = gender;}//在Student类中添加重写的toString(),不然打印的是地址值@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", addr='" + addr + '\'' +", gender=" + gender +'}';}
}

3.创建TestSerializable测试类

package com.sisyphus.serializable;/*@Description: 本类用于测试序列化与反序列化$* @Param: $* @return: $* @Author: Sisyphus* @Date: 7/17$*/import java.io.*;/*** 序列化:是指把程序中的 Java 对象,永久保存到磁盘中,相当于写出的过程* 对应的流的方向:out,对应的序列化流为:ObjectOutputStream* 反序列化:是指把之前已经序列化在文件中保存的数据,读取/恢复到程序* 对应流的方向:in,对应的反序列化流为:ObjectInputStream*/
public class TestSerializable {public static void main(String[] args){method();//测试序列化method2();//测试反序列化}//创建测试反序列化的方法private static void method2() {//定义一个在本方法中都生效的局部变量,初始值为 nullObjectInputStream in = null;try {//1.创建反序列化流对象in = new ObjectInputStream(new FileInputStream("C:\\Users\\admin\\Desktop\\项目文件\\个人项目\\ready\\1.txt"));//进行反序列化Object o = null;o = in.readObject();System.out.println("恭喜你!反序列化成功!");System.out.println(o);} catch (IOException | ClassNotFoundException e) {System.out.println("很抱歉!反序列化失败!");e.printStackTrace();} finally {try {in.close();} catch (IOException e) {e.printStackTrace();}}}//创建测试序列化的方法private static void method() {//1。创建流对象ObjectOutputStream out = null;try {out = new ObjectOutputStream(new FileOutputStream("C:\\Users\\admin\\Desktop\\项目文件\\个人项目\\ready\\1.txt"));//2。使用序列化流进行对象的序列化//2.1准备要输出的对象Student s = new Student("海绵宝宝",3,"海里",'男');//2.2通过 OOS 流对象序列化输出 Student 对象 sout.writeObject(s);System.out.println("恭喜你!序列化成功!");out.writeObject(s);} catch (IOException e) {System.out.println("很抱歉!序列化失败!");e.printStackTrace();} finally {try {out.close();} catch (IOException e) {e.printStackTrace();}}}
}

运行结果:

全参构造
恭喜你!序列化成功!
恭喜你!反序列化成功!
Student{name=‘海绵宝宝’, age=3, addr=‘海里’, gender=男}

三、SerialVersionUID

1.概念

serialVersionUID 是适用于Java的序列化机制,Java的序列化机制是通过判断类的 serialVersionUID 来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的 serialVersionUID 与本地相应实体类的 serialVersionUID 进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是java.io.InvalidClassException

Serializable接口的说明

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java™ Object Serialization Specification.

如果用户没有自己声明一个 serialVersionUID,接口会默认生成一个 serialVersionUID

However, it is stronglyrecommended that all serializable classes explicitly declareserialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpectedInvalidClassExceptions during deserialization.

但是强烈建议用户自定义一个 serialVersionUID,因为默认的 serialVersinUID 对于 class 的细节非常敏感,反序列化时可能会导致 InvalidClassException 这个异常

默认的 serialVersinUID 对于 class 的细节非常敏感

也就是说你创建了一个 Student 类之后,接口会默认生成一个 serialVersionUID = X。然后你将这个 Student 类序列化,然后序列化数据里会保存这个 serialVersionUID = X。然后,你对 Student 类做出一些修改,哪怕仅仅添加一个可有可无的属性,接口都会再次生成一个新的 serialVersionUID,假设新的 serialVersionUID = Y。这个时候你想反序列化恢复之前的对象,但是它们的 serialVersionUID 不一致,这个时候就会报错 InvalidClassException ,那么就很麻烦了,会导致无法恢复之前的对象

2.自定义serialVersinUID

在 Student 类中有这样一行注释

public class Student implements Serializable {//private static final long serialVersionUID = 1L;

这就是自定义 serialVersionUID 的方式
自定义 serialVersionUID 后,不管我们序列化之后如何更改我们的Person,只要不删除原有字段,最终都可以反序列化成功

【JAVA SE】第十三章 序列化与反序列化相关推荐

  1. 当Java泛型擦除遇到JSON序列化和反序列化

    当Java泛型类型擦除遇到JSON序列化和反序列化 目录 当Java泛型类型擦除遇到JSON序列化和反序列化 前言 测试 前言 -最近看到了Spring 关于 RestTemplate的源码实现又有了 ...

  2. Java SE第8章 Java集合

    Java SE第8章 Java集合 1. 集合的概念和作用 2. 使用Lambad表达式遍历集合 3.Collection集合的常规用法 4. 使用Predicate操作集合 5.使用Iterator ...

  3. JAVA进阶教学之(序列化和反序列化)

    目录 1.序列化Serialize和反序列化的概念 2.序列化和反序列化的代码演示: 3.序列化多个对象(序列化集合) 4.transient关键字将部分属性不参与序列化 1.序列化Serialize ...

  4. 【JAVA SE】第一章 Java语言概述、环境变量和HelloWorld

    第一章 Java语言概述.环境变量和HelloWorld 文章目录 第一章 Java语言概述.环境变量和HelloWorld 一.Java语言概述 1.Java简介 2.Java发展历史 3.Java ...

  5. Java对象的serialVersionUID在序列化和反序列化的用途

    本博客主要转自如下链接 http://blog.csdn.net/javazejian/article/details/52665164 这篇文章写的不错,但是有些地方我估计博主没有亲自测试,所以有些 ...

  6. 十三、序列化和反序列化(部分转载)

    json和pickle序列化和反序列化 json是用来实现不同程序之间的文件交互,由于不同程序之间需要进行文件信息交互,由于用python写的代码可能要与其他语言写的代码进行数据传输,json支持所有 ...

  7. java newtonsoft.json_Newtonsoft.Json 的序列化与反序列化

    首先补充一点,Json.Net是支持序列化和反序列化DataTable,DataSet,Entity Framework和NHibernate的.我举例说明DataTable的序列化和反序列化. 创建 ...

  8. java IO(输入输出) 对象的序列化和反序列化

    //对象的序列化 package zhi_jie_liu;import java.io.FileInputStream; import java.io.FileNotFoundException; i ...

  9. Java 中关键字transient引出序列化与反序列化

    一:transient(临时的)关键字 1.transient关键字只能修饰变量,而不能修饰方法和类.注意,本地变量是不能被transient关键字修饰的. 2.被transient关键字修饰的变量不 ...

最新文章

  1. 德布鲁因图和OLC组装基因组
  2. px4驱动linux,px4开发指南——linux下qgroundcontrol地面站安装
  3. android 刷机 备份,安卓刷机后如何还原以前ROM和系统备份
  4. jQuery 获取屏幕高度、宽度
  5. Log4j远程代码执行漏洞验证
  6. 区块链随想:共识不等于信用
  7. log4net使用指南(转载)
  8. python导入gif_Python之GIF图倒放,沙雕快乐源泉!我已经笑了一天了!
  9. 《阿里巴巴Android开发手册》正式发布,献给移动开发者的新年礼物
  10. openstack及组件简要介绍
  11. 使用Secure Boot后,导致VMware无法启动虚拟机
  12. 数组中常用几种的Arrays方法
  13. CentOS6.9 minimal版本安装图形化界面
  14. 计算机编程和机器人编程有什么不同,编程和机器人编程的区别
  15. android brvah 分组,Android开源框架BRVAH由来篇
  16. 谨以此写下本人安装riscv的全过程 简单易懂!!(本人环境是在ubuntu18.04中)
  17. HTML粘性定位,CSS:position——绝对、相对、固定、粘性定位的简单记录
  18. 十进制小数化为二进制小数的方法是什么_二进制的转换
  19. FS\OFS\RS\ORS的使用
  20. exchange 网页无法连接服务器,exchange2016 无法连接服务器

热门文章

  1. java se开发_JAVA_SE基础——3.Java程序的开发流程
  2. ha 配置ssl_HAPROXY 安装SSL证书指南
  3. C#图解教程 第十八章 枚举器和迭代器
  4. python/socket编程之粘包
  5. GoF23种设计模式之行为型模式之策略模式
  6. 我学习设计模式的一些所想所得
  7. Web压力测试工具 - Siege
  8. Silverlight动画基础三:动画与向量-模拟重力效果
  9. 基于FPGA实现IIC接口(EEPROM)
  10. (73)多路选择器(二选一)