Java序列化和反序列化(详解)

2023-11-14

一、理解Java序列化和反序列化

Serialization(序列化)将java对象以一连串的字节保存在磁盘文件中的过程,也可以说是保存java对象状态的过程。序列化可以将数据永久保存在磁盘上(通常保存在文件中)。

deserialization(反序列化)将保存在磁盘文件中的java字节码重新转换成java对象称为反序列化。

二、序列化和反序列化的应用

两个进程在远程通信时,可以发送多种数据,包括文本、图片、音频、视频等,这些数据都是以二进制序列的形式在网络上传输。

java是面向对象的开发方式,一切都是java对象,想要在网络中传输java对象,可以使用序列化和反序列化去实现,发送发需要将java对象转换为字节序列,然后在网络上传送,接收方收到字符序列后,会通过反序列化将字节序列恢复成java对象。

java序列化的优点:

  • 实现了数据的持久化,通过序列化可以把数据持久地保存在硬盘上(磁盘文件)。
  • 利用序列化实现远程通信,在网络上传输字节序列。

三、序列化和反序列化地实现

1.JDK类库提供的序列化API:

  • java.io.ObjectOutputStream    
    表示对象输出流,其中writeObject(Object obj)方法可以将给定参数的obj对象进行序列化,将转换的一连串的字节序列写到指定的目标输出流中。
  • java.io.ObjectInputStream
    该类表示对象输入流,该类下的readObject(Object obj)方法会从源输入流中读取字节序列,并将它反序列化为一个java对象并返回。

序列化要求:

实现序列化的类对象必须实现了Serializable类或Externalizable类才能被序列化,否则会抛出异常。

实现java序列化和反序列化的三种方法:

现在要对student类进行序列化和反序列化,遵循以下方法:

方法一:若student类实现了serializable接口,则可以通过objectOutputstream和objectinputstream默认的序列化和反序列化方式,对非transient的实例变量进行序列化和反序列化。

方法二:若student类实现了serializable接口,并且定义了writeObject(objectOutputStream out)和

readObject(objectinputStream in)方法,则可以直接调用student类的两种方法进行序列化和反序列化。

方法三:若student类实现了Externalizable接口,则必须实现readExternal(Objectinput in)和writeExternal(Objectoutput out)方法进行序列化和反序列化。

JDK类库中的序列化步骤:

第一步:创建一个输出流对象,它可以包装一个输出流对象,如:文件输出流。

ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream("E:\\JavaXuLiehua\\Student\\Student1.txt"));

 第二步:通过输出流对象的writeObject()方法写对象

out.writeObject("hollo word");

out.writeObject("happy")

 JDK中反序列化操作:

第一步:创建文件输入流对象

 ObjectInputStream in = new ObjectInputStream(new fileInputStream("E:\\JavaXuLiehua\\Student\\Student1.txt"));

 第二步:调用readObject()方法

 String obj1 = (String)in.readObject();

 String obj2 = (String)in.readObject();

 为了保证正确读取数据,对象输出流写入对象的顺序与对象输入流读取对象的顺序一致。

 Student类序列化和反序列化演示:

1.先创建一个继承了serializable类的student类

import java.io.Serializable;            //导入io包下的序列化类

//创建实现序列化接口的学生类
public class Student implements Serializable {
    //私有化成员变量
    private String name;
    private  char sex;
    private  int year;
    private  double gpa;

    public Student(){   //无参构造
    }
    public Student(String name,char sex,int year,double gpa){
        //参数给属性赋值
        this.name = name;
        this.sex = sex;
        this.year = year;
        this.gpa = gpa;
    }

    //重写set和get
    public String getName() {
        return name;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public double getGpa() {
        return gpa;
    }

    public void setGpa(double gpa) {
        this.gpa = gpa;
    }
}

把Student类的对象序列化到txt文件(E:\\JavaXuLiehua\\Student\\Student1.txt)中,并对文件进行反序列化:

import java.io.*;
import java.io.Externalizable;
/*
把student类对象序列化到文件E:\\JavaXuLiehua\\Student\\Student1.txt
 */
public class UserStudent {
    public static void main(String[] args) throws IOException {
        Student st = new Student("Tom",'M',20,3.6);         //实例化student类
        //判断Student1.txt是否创建成功
        File file = new File("E:\\JavaXuLiehua\\Student\\Student1.txt");
        if(file.exists()) {
            System.out.println("文件存在");
        }else{
            //否则创建新文件
            file.createNewFile();
        }
        try {
            //Student对象序列化过程
            FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            //调用 ObjectOutputStream 中的 writeObject() 方法 写对象
            oos.writeObject(st);
            oos.flush();        //flush方法刷新缓冲区,写字符时会用,因为字符会先进入缓冲区,将内存中的数据立刻写出
            fos.close();
            oos.close();

            //Student对象反序列化过程
            FileInputStream fis = new FileInputStream(file);
            //创建对象输入流
            ObjectInputStream ois = new ObjectInputStream(fis);
            //读取对象
            Student st1 = (Student) ois.readObject();           //会抛出异常(类找不到异常)
            System.out.println("name = " + st1.getName());
            System.out.println("sex = " + st1.getSex());
            System.out.println("year = " + st1.getYear());
            System.out.println("gpa = " + st1.getGpa());
            ois.close();
            fis.close();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
    }
}

 查看txt文件,结果如下:

 sr JavaxulieHua.Studentd9Q藿Hf D gpaC sexI yearL namet Ljava/lang/String;xp@ 烫烫掏 M   t Tom

 可以看出其中的内容是不容易阅读的,只能通过反序列化读取。

四、transient关键字

transient关键字表示有理的,被修饰的数据不能进行序列化

这里不做详细介绍,修改情况如下:

private transient char sex;         //被transient关键字修饰,不参与序列化

 运行结果如下:

文件存在
name = Tom
sex =  
year = 20
gpa = 3.6

此时可以看见,被transient关键字修饰的变量sex并没有被序列化,返回了空值。

五、Externalizable接口实现序列化与反序列化

Externalizable接口继承Serializable接口,实现Externalizable接口需要实现readExternal()方法和writeExternal()方法,这两个方法是抽象方法,对应的是serializable接口的readObject()方法和writeObject()方法,可以理解为把serializable的两个方法抽象出来。Externalizable没有serializable的限制,static和transient关键字修饰的属性也能进行序列化。

具体代码实现如下:

复制对象student命名为student1,在里面重写writeExternal()方法和readExternal()方法,如下:

   @Override
    //对抽象方法进行重写
    public void writeExternal(ObjectOutput out) throws IOException{
        out.writeObject(name);
        out.writeObject(sex);
        out.writeObject(year);
        out.writeObject(gpa);
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        sex = (char) in.readObject();
        year = (int) in.readObject();
        gpa = (double) in.readObject();
    }

相应的测试方法里面调用这两种方法的时候,直接调用writeObject()方法和readObject()方法即可,重写的writeExternal()和readExternal()方法会自动执行。

FileOutputStream fos1 = new FileOutputStream(file1);
                ObjectOutputStream oos1 = new ObjectOutputStream(fos1);
                //调用 ObjectOutputStream 中的 writeObject() 方法 写对象
                oos1.writeObject(st);       //会自动执行重写的writeExternal()方法
FileInputStream fis1 = new FileInputStream(file1);
                //创建对象输入流
                ObjectInputStream ois1 = new ObjectInputStream(fis1);
                //读取对象
                //会自动执行readExternal()方法
                Student1 st1 = (Student1) ois1.readObject();           //会抛出异常(类找不到异常)

虽然student1类里的sex属性被static或transient修饰,但依旧被序列化,结果如下:

文件存在
name = Tom
sex = M
year = 20
gpa = 3.6

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java序列化和反序列化(详解) 的相关文章

  • 获取文件的锁

    我想在对特定文件开始 threo read 时获取文件上的锁定 以便其他应用程序无法读取已锁定的文件并希望在线程终止时释放锁定文件 您可以获得一个FileLock https docs oracle com javase 8 docs ap
  • 如何在 Openfire 中使用 smack

    你好 我计划开发一个可以连接到 gtalk facebook 等的聊天客户端 我决定将 smack API 与 openfire 一起使用 但我需要很少的指导来了解如何将它与 openfire 服务器一起使用 openfire 是否提供了基
  • 当路径的点超出视野时,Android Canvas 不会绘制路径

    我在绘制路径时遇到了 Android Canvas 的一些问题 我的情况是 我有一个相对布局工作 如地图视图 不使用 google api 或类似的东西 我必须在该视图上绘制一条路径 canvas drawPath polyPath bor
  • 如何将jscrollpane添加到jframe?

    我有以下源代码 有人可以给我建议如何将 jscrollpane 添加到 jframe 上吗 我尝试了几次将其添加到 jframe 但没有任何进展 它甚至没有显示 public class Form3 JFrame jframe new JF
  • Reactive Spring 不支持 HttpServletRequest 作为 REST 端点中的参数?

    我创建了一个 RestController 如下所示 RestController public class GreetingController RequestMapping value greetings method RequestM
  • 为自定义驱动程序创建 GraphicsDevice

    我正在开发一个在嵌入式系统中使用 Java 的项目 我有用于屏幕和触摸输入的驱动程序 以及用于文本输入的虚拟键盘 我的屏幕驱动程序有一个Graphics2D您可以绘制的对象和repaint Rectangle 更新方法 类似地 触摸驱动器能
  • Spring数据中的本机查询连接

    我有课 Entity public class User Id Long id String name ManyToMany List
  • 如何通过注解用try-catch包装方法?

    如果应该在方法调用中忽略异常 则可以编写以下内容 public void addEntryIfPresent String key Dto dto try Map
  • 在 Java 中通过 XSLT 分解 XML

    我需要转换具有嵌套 分层 表单结构的大型 XML 文件
  • Java、Spring:使用 Mockito 测试 DAO 的 DataAccessException

    我正在尝试增加测试覆盖率 所以我想知道 您将如何测试 DAO 中抛出的 DataAccessExceptions 例如在一个简单的 findAll 方法中 该方法仅返回数据源中的所有数据 就我而言 我使用 Spring JdbcTempla
  • 用于缓存的 Servlet 过滤器

    我正在创建一个用于缓存的 servlet 过滤器 这个想法是将响应主体缓存到memcached 响应正文由以下方式生成 结果是一个字符串 response getWriter print result 我的问题是 由于响应正文将不加修改地放
  • 如何通过 Android 按钮单击运行单独的应用程序

    我尝试在 Android 应用程序中添加两个按钮 以从单独的两个应用程序订单系统和库存系统中选择一个应用程序 如图所示 我已将这两个应用程序实现为两个单独的 Android 项目 当我尝试运行此应用程序时 它会出现直到正确选择窗口 但是当按
  • Karaf / Maven - 无法解决:缺少需求 osgi.wiring.package

    我无法在 Karaf 版本 3 0 1 中启动捆绑包 该包是使用 Maven 构建的并导入gson http mvnrepository com artifact com google code gson gson 2 3 1 我按照要求将
  • 使用Java绘制维恩图

    我正在尝试根据给定的布尔方程绘制维恩图 例如 a AND b AND c我想在 Android 手机上执行此操作 因此我需要找到一种使用 Java 来执行此操作的方法 我找到了一个完美的小部件 它可以完成我在这方面寻找的一切布尔代数计算器
  • 我可以限制分布式应用程序发出的请求吗?

    我的应用程序发出 Web 服务请求 提供商处理的请求有最大速率 因此我需要限制它们 当应用程序在单个服务器上运行时 我曾经在应用程序级别执行此操作 一个对象跟踪到目前为止已发出的请求数量 并在当前请求超出允许的最大负载时等待 现在 我们正在
  • 如何在Java中对对象数组进行字段级别排序以进行等级比较?

    In Java Class StudentProgress String Name String Grade CTOR goes here main class main method StudentProgress arrayofObje
  • 如何处理 StaleElementReferenceException

    我正在为鼠标悬停工作 我想通过使用 for 循环单击每个链接来测试所有链接的工作条件 在我的程序中 迭代进行一次 而对于下一次迭代 它不起作用并显示 StaleElementReferenceException 如果需要 请修改代码 pub
  • 源值 1.5 的错误已过时,将在未来版本中删除

    我使用 scala maven plugin 来编译包含 scala 和 java 代码的项目 我已经将源和目标设置为1 7 但不知道为什么maven仍然使用1 5 这是我在 pom xml 中的插件
  • HttpClient请求设置属性问题

    我使用这个 HttpClient 库玩了一段时间 几周 我想以某种方式将属性设置为请求 不是参数而是属性 在我的 servlet 中 我想使用 Integer inte Integer request getAttribute obj 我不
  • 即使调整大小,如何获得屏幕的精确中间位置

    好的 这个问题有两部分 当我做一个JFrame 并在其上画一些东西 即使我将宽度设置为 400 并使其在一个项目击中它时 当然 允许项目宽度 它会反弹回来 但由于某种原因 它总是偏离屏幕约 10 个像素 有没有办法解决这个问题 或者我只需要

随机推荐

  • Java Stream 实用特性:排序、分组和 teeing

    排序 基本数据类型排序 基本数据类型就是字符串 整型 浮点型这些 也就是要排序的列表中的元素都是这些基本类型的 比如 List
  • C#__资源访问冲突和死锁问题

    线程的资源访问冲突 多个线程同时申请一个资源 造成读写错乱 解决方案 上锁 lock 执行的程序段 同一时刻 只允许一个线程访问该程序段 死锁问题 程序中的锁过多 某一线程需要多个锁资源 而某个资源被另一线程占用 另一个线程同样如此 谁也不
  • 【mysql索引】之多列索引

    第零步 简单说一说 多列索引并不是指建立多个单列索引 而是指在多个字段建立一个索引 在多个列上建立独立的单列索引大部分情况下并不能提高MySQL的查询性能 MySQL在5 0之后推出了索引合并策略 index merge 一定程度上可以使用
  • 解决哥斯拉内存马 pagecontext 的问题

    零基础学黑客 搜索公众号 白帽子左一 前言 注入内存马借助当前的webshell工具而言 冰蝎可以通过创建hashmap放入request response session替换pagecontext来解决 HttpSession sessi
  • Failed to encrypt the section connectionStrings using provider RsaProtectedConfigurationProvider

    使用aspnet regiis exe加密web config connectionStrings时奇奇怪怪的错误 Failed to encrypt the section connectionStrings using provider
  • java必刷题——正则表达式

    题目 需求分析 解题思路 获取用户输入的 需矫正字符总数 根据用户输入的 总数 对错误字符进行矫正 技术栈 java正则表达式 代码实现 package OpenClosedPrinciple import java util Scanne
  • OAuth2.0认证原理浅析

    一 OAuth是什么 OAuth的英文全称是Open Authorization 它是一种开放授权协议 OAuth目前共有2个版本 2007年12月的1 0版 之后有一个修正版1 0a 和2010年4月的2 0版 1 0版本存在严重安全漏洞
  • 深入浅出——搞懂卷积神经网络的过拟合、梯度弥散、batchsize的影响的问题(二)

    上一篇主要是对卷积神经网络的整个训练过程中公式以及误差的推导给出详细的分析 博客地址 http blog csdn net u010402786 article details 51226825 这一篇主要对卷积神经网络中出现的一些问题进行
  • 网站更换域名后链接的更改(运维端)

    公司由于备案的问题 需要将域名www servera com更换为www serverb com 但是原先网站所有链接均指向www servera com 这个时候可以通过2种方法 1 在负载均衡器增加301跳转 这样打开每个www ser
  • 阿里云ecs.u1-c1m1.large服务器u1实例通用算力型CPU性能评测

    阿里云服务器ecs u1 c1m1 large为2核2G的通用算力型u1服务器 CPU采用2 5 GHz主频的Intel Xeon Platinum 8163 Skylake 或者8269CY Cascade Lake 阿里云百科分享阿里云
  • Use a SAML Token to Obtain a vCloud Suite Session ID ----使用SAML 令牌 获取VCloud 会话ID

    原文 span style font size 12px Another case is when the client requests a vCloud Suite endpoint on the management node the
  • Web components新玩具——X-View

    X View是一款遵循Web Components规范 类似React语法的JavaScript library 支持的特性 Object assign WeakMap Custom Elements Shadow DOM
  • JS调试日志输出和异常处理

    一 直接启用浏览器调试功能 Chrome浏览器中 1 按下F12打开调试界面 2 选择source选项卡 选中script文件打开 3 单击行增删断点 F10单步调试 F11进入函数 F8下一个断点 鼠标移动到变量上可以查看该变量的值 4
  • 信号量、互斥体和自旋锁的区别

    cpp view plaincopyprint 信号量 互斥体允许进程睡眠属于睡眠锁 自旋锁则不允许调用者睡眠 而是让其循环等待 所以有以下区别应用 1 信号量和读写信号量适合于保持时间较长的情况 它们会导致调用者睡眠 因而自旋锁适合于保持
  • 什么是算法?

    算法 解决特定问题求解步骤的描述 在计算机中表现为指令的有限序列 并且每条指令表示一个或多个操作 算法特性 输入 输出 有穷性 确定性 可行性 算法设计的要求 正确性 1 算法程序没有语法错误 2 算法程序对于合法输入数据能够产生满足要求的
  • cmake设定项目版本信息

    一 version h in模板文件 pragma once define VER MAJOR 1 define VER MINOR 0 define VER BUILD 1 define VER REVISION PROJECT REVI
  • C#试题

    1 关于C 中的结构 一下说法中错误的是 选择一项 A 结构可以有构造函数 B 结构体内可以有字段 C 结构体内可以有方法 D 结构体内可以被继承 2 在C 编程中 访问修饰符控制程序对类中成员的访问 如果不写访问修饰符 类的默认访问类型是
  • excludePathPatterns方法不生效

    1 场景 我在项目中配置了License证书授权的功能 然后在配置拦截器的时候拦截了所有的请求都必须验证License是否到期 但是这样会导致接口响应慢 所以打算使用 excludePathPatterns 方法对部分url请求放行 例如我
  • element UI 表格table多个数值进行排序筛选

    效果图 1 表格html部分
  • Java序列化和反序列化(详解)

    一 理解Java序列化和反序列化 Serialization 序列化 将java对象以一连串的字节保存在磁盘文件中的过程 也可以说是保存java对象状态的过程 序列化可以将数据永久保存在磁盘上 通常保存在文件中 deserializatio