Java中序列化和反序列化的完整讲解

目录
  • 一、序列化
  • 二、序列化和反序列化的应用
  • 三、序列化和反序列化地实现
    • 3.1.JDK类库提供的序列化API
    • 3.2.序列化要求
    • 3.3.实现java序列化和反序列化的三种方法
  • 四、CustomerForm 类序列化和反序列化演示
  • 五、Externalizable接口实现序列化与反序列化
    • 5.1.Externalizable 的不同点
    • 5.2.CustomerForm 实现类 Externalizable
    • 5.3.Externalizable 实现序列化和反序列化
  • 总结

一、序列化

1.1.Serialization(序列化):

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

1.2.deserialization(反序列化)

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

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

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

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

java序列化的优点:

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

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

3.1.JDK类库提供的序列化API

java.io.ObjectOutputStream

表示对象输出流,其中writeObject(Object obj)方法可以将给定参数的obj对象进行序列化,将转换的一连串的字节序列写到指定的目标输出流中。

java.io.ObjectInputStream

该类表示对象输入流,该类下的readObject(Object obj)方法会从源输入流中读取字节序列,并将它反序列化为一个java对象并返回

3.2.序列化要求

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

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

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

3.3.1.方法一

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

3.3.2. 方法二

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

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

3.3.3.方法三

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

3.4.序列化步骤 

public static void main(String[] args) {
    File filename = new File("E:/Student1.txt");
    try {
            // 第一步,创建一个输出流对象,它可以包装一个输出流对象,如:文件输出流
            FileOutputStream fileOutputStream = new FileOutputStream(filename);
            ObjectOutputStream out = new ObjectOutputStream(fileOutputStream);
            // 第二步,通过输出流对象的 writeObject()方法写对象,从 java 输出到本地文件 out
            out.writeObject("第一次输出:第一次打卡哦");
            out.writeObject("第二次输出:第二次打卡");
    } catch (IOException e) {
            e.printStackTrace();
    }
}

3.5.反序列化操作

public static void main(String[] args) {
    File filename = new File("E:/Student1.txt");
    try {
            // 第一步:创建文件输入流对象
            FileInputStream fileInputStream = new FileInputStream(filename);
            ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
            // 调用readObject()方法,本地文件读取数据,输入到程序当中
            System.out.println(inputStream.readObject());
            System.out.println(inputStream.readObject());
    } catch (IOException e) {
            e.printStackTrace();
    } catch (ClassNotFoundException e) {
            e.printStackTrace();
    }
}

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

四、CustomerForm 类序列化和反序列化演示

4.1.先创建一个实现了serializable接口的CustomerForm 类

Serializable (/ˈsɪˌriəˌlaɪzəbl/) 序列化

import lombok.Data;
import java.io.Serializable;
import java.util.List;

/**
 * <p>Java class for attachmentForm complex type.
 *
 */
@Data
public class CustomerForm implements Serializable {
    protected String requestCode;
    protected List<Customer> reqData;
    /**
     * transient 修饰的属性不能序列化 *
     */
    private transient String msg;
    private static String name = "被static修饰的name";
}

把CustomerForm类的对象序列化到CustomerForm.txt 文件(E:/CustomerForm.txt)中,并对文件进行反序列化获取数据:

public static void main(String[] args) {
    FileOutputStream fileOutputStream = null;
    ObjectOutputStream out = null;
    FileInputStream fileInputStream = null;
    ObjectInputStream inputStream = null;
    try {
        File file = new File("E:/CustomerForm.txt");
        if (file.exists()){
            System.out.println("文件已存在");
        } else {
            file.createNewFile();
        }
        CustomerForm customerForm = new CustomerForm();
        customerForm.setRequestCode("1-2-3-4-5-6-7-8-9");
        // 序列化 第一步,创建一个输出流对象,它可以包装一个输出流对象,如:文件输出流
        fileOutputStream = new FileOutputStream(file);
        out = new ObjectOutputStream(fileOutputStream);
        // 序列化 第二步,通过输出流对象的 writeObject()方法写对象,从 java 输出到本地文件 out
        out.writeObject(customerForm);
        // 反序列化 第一步:创建文件输入流对象
        fileInputStream = new FileInputStream(file);
        inputStream = new ObjectInputStream(fileInputStream);
        // 反序列化 第二步:调用readObject()方法,本地文件读取数据,输入到程序当中
        System.out.println(inputStream.readObject());
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        out.close();
        fileOutputStream.close();
        fileInputStream.close();
        inputStream.close();
    }
}

序列化之后本地文件访问结果:

反序列化结果:

4.2.transient 关键字

transient ( /ˈtrænʃ(ə)nt/)瞬变的

transient 修饰的属性不能参加序列化

以上程序重新执行:

public static void main(String[] args) {
    try {
        File file = new File("E:/CustomerForm.txt");
        if (file.exists()){
            System.out.println("文件已存在");
        } else {
            file.createNewFile();
        }
        CustomerForm customerForm = new CustomerForm();
        customerForm.setRequestCode("1-2-3-4-5-6-7-8-9");
        /**
         * transient 修饰的属性不能序列化 *
         */
        customerForm.setMsg("此属性不能参加序列化");
        // 序列化 第一步,创建一个输出流对象,它可以包装一个输出流对象,如:文件输出流
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        ObjectOutputStream out = new ObjectOutputStream(fileOutputStream);
        // 序列化 第二步,通过输出流对象的 writeObject()方法写对象,从 java 输出到本地文件 out
        out.writeObject(customerForm);
        // 反序列化 第一步:创建文件输入流对象
        FileInputStream fileInputStream = new FileInputStream(file);
        ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
        // 反序列化 第二步:调用readObject()方法,本地文件读取数据,输入到程序当中
        System.out.println(inputStream.readObject());
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

执行结果:

从结果看出 被transient关键字修饰的变量 msg 赋值内容没有被序列化,被修改为null,被static修饰的属性不能被实例化

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

Externalizable 可外部化的

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

5.1.Externalizable 的不同点

Externalizable没有serializable的限制,transient关键字修饰的属性也能进行序列化

5.2.CustomerForm 实现类 Externalizable

import lombok.Data;
import java.io.Serializable;
import java.util.List;

/**
 * <p>Java class for attachmentForm complex type.
 *
 */
@Data
public class CustomerForm implements Externalizable{
    protected String requestCode;
    protected List<Customer> reqData;
    private transient String msg;
    private static String name = "被static修饰的name";

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(requestCode);
        out.writeObject(msg);
        out.writeObject(reqData);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        requestCode = (String) in.readObject();
        msg = (String) in.readObject();
        reqData = (List<Customer>) in.readObject();
    }
}

实现 Externalizable 类 后需要重写 writeExternal()、readExternal() 方法

5.3.Externalizable 实现序列化和反序列化

public static void main(String[] args) {
    try {
        File file = new File("E:/CustomerForm.txt");
        if (file.exists()){
            System.out.println("文件已存在");
        } else {
            file.createNewFile();
        }
        CustomerForm customerForm = new CustomerForm();
        customerForm.setRequestCode("1-2-3-4-5-6-7-8-9");
        customerForm.setMsg("该属性被transient修饰");
        // 序列化 第一步,创建一个输出流对象,它可以包装一个输出流对象,如:文件输出流
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        ObjectOutputStream out = new ObjectOutputStream(fileOutputStream);
        // 序列化 第二步,通过输出流对象的 writeObject()方法写对象,从 java 输出到本地文件 out
        out.writeObject(customerForm);
        // 反序列化 第一步:创建文件输入流对象
        FileInputStream fileInputStream = new FileInputStream(file);
        ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
        // 反序列化 第二步:调用readObject()方法,本地文件读取数据,输入到程序当中
        System.out.println(inputStream.readObject());
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

执行结果:

可以看到被transient关键字修饰的变量msg已经参与了实例化,被static修饰的变量不能被实例化

总结

序列化和反序列化可以过这两种方式来实现:

1、Bean对象可以通过Serializable接口实现序列化与反序列化

2、Bean对象可以通过Externalizable接口实现序列化与反序列化

不同点

1、Externalizable接口实现实例化,需要重写 writeExternal()、readExternal() 方法

2、Externalizable接口实现实例化,不受 transient关键字限制

3、Serializable接口实现,transient关键字修饰后,不能参与实例化

4、被static修饰的变量(都)不能被实例化

原因:被static修饰的属性是所有类共享的,如果可以序列化,就会出现下面的情况,当我们序列化某个类的一个对象到某个文件后,这个文件中的对象的那个被static修饰的属性值会固定下来,当另外一个普通的的对象修改了该static属性后,我们再去反序列化那个文件中的对象,就会得到和后面的对象不同的static属性值,这显然违背了static关键字诞生的初衷

到此这篇关于Java中序列化和反序列化的完整讲解的文章就介绍到这了,更多相关Java序列化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一文带你彻底理解Java序列化和反序列化

    Java序列化是什么? Java序列化是指把Java对象转换为字节序列的过程,Java反序列化是指把字节序列恢复为Java对象的过程. 反序列化: 客户端重文件,或者网络中获取到文件以后,在内存中重构对象. 序列化: 对象序列化的最重要的作用是传递和保存对象的时候,保证对象的完整性和可传递性.方便字节可以在网络上传输以及保存在本地文件. 为什么需要序列化和反序列化 实现分布式 核心在于RMI,可以利用对象序列化运行远程主机上的服务,实现运行的时候,就像在本地上运行Java对象一样. 实现递归保存

  • Java基础之序列化与反序列化详解

    目录 1.什么是序列化与反序列化? 2.Java如何实现序列化和反序列化? 3.如何自定义序列化和反序列化呢? 4.writeObject和readObject方法 5.serializable接口 1.什么是序列化与反序列化? 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等.在网络传输过程中,可以是字节或是XML等格式.而字节的或XML编码格式可以还原完全相等的对象.这个相反的过程又称为反序列

  • 图文浅析Java序列化和反序列化

    序列化 序列化:将对象转换为二进制序列在网络中传输或保存到磁盘 反序列化:从网络或磁盘中将二进制序列转换为对象 注意: 对象必须实现Serializable接口 对象的所有属性都要能序列化(Integer,Byte等都进行了序列化) String Integer 案例: 1.编写大象类 public class Elephant implements Serializable { private String name; private String age; private String se

  • Java序列化和反序列化示例介绍

    以前用序列化都是一些方法需要才实现的,后来业务需求要深拷贝才去研究.参阅了别人博客得出一些总结. 序列化是为了把Java对象转化为字节序列(字节流)的过程.然后深拷贝是通过对流的操作来实现的,序列化后数据方便存储和传输.反序列化则是把字节序列反序列化为Java对象 存储方便:因为对象会被回收,序列化后可以持续化存储在磁盘中传输方便:字节序列(二进制形式)可以进行网络传输和传播. 最好设置一个SerialversionUID,因为序列化和反序列化是对比SerialversionUID来进行的,虽然

  • 一文搞懂Java中的序列化与反序列化

    目录 序列化和反序列化的概念 应用场景 序列化实现的方式 继承Serializable接口,普通序列化 继承Externalizable接口,强制自定义序列化 serialVersionUID的作用 静态变量不会被序列化 使用序列化实现深拷贝 常见序列化协议对比 小结 序列化和反序列化的概念 当我们在Java中创建对象的时候,对象会一直存在,直到程序终止时.但有时候可能存在一种"持久化"场景:我们需要让对象能够在程序不运行的情况下,仍能存在并保存其信息.当程序再次运行时 还可以通过该对

  • 深入理解Java序列化与反序列化

    一.前言 序列化:将对象转换为二进制序列在网络中传输或保存到磁盘 反序列化:从网络或磁盘中将二进制序列转换为对象 注意: 对象必须实现Serializable接口 对象的所有属性都要能序列化(Integer,Byte等都进行了序列化) 1.1 String 1.2 Integer 二.案例 2.1 编写大象类 public class Elephant implements Serializable { private String name; private String age; priva

  • Java中序列化和反序列化的完整讲解

    目录 一.序列化 二.序列化和反序列化的应用 三.序列化和反序列化地实现 3.1.JDK类库提供的序列化API 3.2.序列化要求 3.3.实现java序列化和反序列化的三种方法 四.CustomerForm 类序列化和反序列化演示 五.Externalizable接口实现序列化与反序列化 5.1.Externalizable 的不同点 5.2.CustomerForm 实现类 Externalizable 5.3.Externalizable 实现序列化和反序列化 总结 一.序列化 1.1.S

  • 一篇文章带你了解Java 中序列化与反序列化

    目录 一. 序列化和反序列化概念 二. 序列化和反序列化的必要性 三. 序列化和反序列化的实现 1. JDK类库提供的序列化API 2. 实现序列化的要求 3. 实现Java对象序列化与反序列化的方法 4. JDK类库中序列化的步骤 5. JDK类库中反序列化的步骤 四.序列化的必要条件 五.序列化高级,使用情境分析 1. 序列化ID问题 特性使用案例 2. 静态变量序列化 3. 父类的序列化与 Transient 关键字 4. 对敏感字段加密 5. 序列化存储规则 总结 一. 序列化和反序列化

  • java 中序列化与readResolve()方法的实例详解

    java 中序列化与readResolve()方法的实例详解 readResolve方法是作用是什么?这个方法跟对象的序列化相关(这样倒是解释了为什么 readResolve方法是private修饰的). 怎么跟对象的序列化相关了? 下面我们先简要地回顾下对象的序列化.一般来说,一个类实现了 Serializable接口,我们就可以把它往内存地写再从内存里读出而"组装"成一个跟原来一模一样的对象.不过当序列化遇到单例时,里边就有了个问题:从内存读出而组装的对象破坏了单例的规则.单例是要

  • java中list的用法和实例讲解

    目录: list中添加,获取,删除元素: list中是否包含某个元素: list中根据索引将元素数值改变(替换): list中查看(判断)元素的索引: 根据元素索引位置进行的判断: 利用list中索引位置重新生成一个新的list(截取集合): 对比两个list中的所有元素: 判断list是否为空: 返回Iterator集合对象: 将集合转换为字符串: 将集合转换为数组: 集合类型转换: 去重复: 备注:内容中代码具有关联性. 1.list中添加,获取,删除元素: 添加方法是:.add(e): 获

  • java对象序列化与反序列化原理解析

    这篇文章主要介绍了java对象序列化与反序列化原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.序列化和反序列化的概念 对象转换为字节序列的过程称为对象的序列化.把字节序列恢复为对象的过程称为对象的反序列化. 二.序列化和反序列化的作用 对象的序列化主要有两种用途: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中. 在网络上传送对象的字节序列.网络上传输的都是二进制序列. 在很多应用中,需要对某些对象进行序列化,让它们离开内

  • Go语言中序列化与反序列化示例详解

    目录 前言 序列化 array.slice.map.struct对象 序列化的接口 反序列化 slice.map.struct反序列化 总结 前言 Go语言的序列化与反序列化在工作中十分常用,在Go语言中提供了相关的解析方法去解析JSON,操作也比较简单 序列化 // 数据序列化 func Serialize(v interface{})([]byte, error) // fix参数用于添加前缀 //idt参数用于指定你想要缩进的方式 func serialization (v interfa

  • java 中序列化NotSerializableException问题解决办法

    java 中序列化NotSerializableException问题解决办法 前言: 某项目中,要将某个自定义类MMessage对象,通过ObjectOutputStream和ObjectInputStream传递,该MMessage的特征描述: 1 该类未继承Serializable接口: 2 其父类Message的父类继承了Serializable接口: 3 其父类中有一个字段类型为Java.io.ByteArrayOutputStream类型: 经测试发现,MMessage类序列化过程中

  • java 中动态代理机制的实例讲解

    java 中动态代理机制的实例讲解 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾. 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)

  • 基于Java中UDP的广播形式(实例讲解)

    UDP---用户数据报协议,是一个简单的面向数据报的运输层协议.UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地 ,也不能保证数据包到达的顺序.由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快. 在Java中UDP的实现: * UDP: * 客户端: * 1.创建用于UDP通信的socket对象---DatagramSocket(用于UDP数据的发送和接收)---数据报套接字 * 2.准备数据,封装包

  • Django框架中序列化和反序列化的例子

    1.序列化 DRF的核心 就是 前后端分离的核心 前后端分离开发的核心: 将模型转换为json 称之为 序列化 将json转换为模型 称之为 反序列化 1.序列化器的字段 Serializer 序列化器 为了得到模型里的字段,序列化器中的字段应与模型类中的字段名一致 ''' serializers.py ''' class BookInfoSerializer(serializers.Serializer): # read_only=True 只能读 不能修改 id = serializers.

随机推荐