Java序列化

简介: Java序列化

Java序列化

WHAT 什么是序列化

序列化(Serialization):指将对象转换成可传输格式的过程,以便在需要时可以将其还原成原始对象。


在Java中,对象序列化将对象转换为一系列字节流,这些字节流可以写入文件或通过网络传输,并且可以在需要时重新创建相同的对象。


WHY 为什么java要进行序列化

java中进行序列化可以使java对象在网上传输或者在不同进程之间进行传输,可以将java对象保存到磁盘上以便之后使用,可以提高应用程序的性能,还可以用于实现分布式计算。


1.远程调用(RPC)Remote Procedure Call,在分布式系统中,远程调用(RPC)是一种常见的通信方式,通过序列化Java对象可以将方法调用参数和返回值在不同的进程之间传递,使得分布式系统的开发更加方便。


2.持久化:在Java中,可以使用对象序列化将Java对象保存到磁盘上,以便之后的使用。这样做的好处是可以减少对象的初始化时间,并且可以避免频繁地从数据库或其他存储介质中读取数据。


3.缓存:在某些场景下,将Java对象序列化并存储在缓存中可以提高应用程序的性能,因为对象在缓存中可以更快地被加载和使用。


4.分布式计算:在分布式计算中,Java对象序列化是实现数据共享和数据传输的一种有效方式。


那除了使用序列化的方式让java对象在网络传输以及持久化,那还有其他方式吗?

1.使用JSON或XML等数据格式:将Java对象转换为JSON或XML格式的数据,以便于进行网络传输或持久化存储。这种方式相对于序列化来说更灵活,可以在不同的语言之间进行数据交互,但是也需要一定的转换成本。

2.数据库存储:将 Java 对象的数据存储在关系型或非关系型数据库中,可以使用 JPA、Hibernate、MyBatis 等 ORM 框架将 Java 对象映射为数据库表,然后进行持久化。。

本质都是将该格式转成二进制流进行传输、存储。注意二进制是一种数据技术方式,计算机中所以的数据都是以二进制形式进行存储,而二进制流是计算机中以二进制形式流动的数据,二进制流是指多个字节组成的数据流,包括文本、图像等各种类型的数据,它们在计算机中都是以二进制流的形式进行存储。


WHEN 一般什么情况下需要进行序列化

1.对象需要在网络上传输:因为在网络上传输数据时,数据必须以二进制形式进行传输,而java对象通常是以内存中的对象形式存在的,因此需要将java对象序列化为字节流后才能进行网络传输。

2.对象需要在不同的进程或者计算机之间传递:因为不同的进程或计算机之间无法直接共享内存,java对象在不同系统中可能具有不同的内存布局,需要将java对象序列化为字节流后才能在不同的进程或计算机之间进行传递。

3.对象需要持久化存储时:因为将Java对象保存到磁盘上,必须将Java对象序列化为字节流之后才能进行存储。

补充:字节流与二进制是什么关系?

我们都知道在计算机中,所有数据都是以二进制形式存储的,因此字节流本质上就是二进制流。

在Java中字节流可以看做是二进制流的抽象,它是一组用于读写二进制数据的API,可以通过它来读取、写入二进制数据,包括文件等。


字节流在Java中的实现类有两种:InputStream和OutputStream,可以用来读写字节流。通常我们会使用字节流来读取和写入二进制数据。

例如:音频文件、视频文件、图片等等。而在将Java对象进行序列化时,也是将java对象转换为字节流的形式,以便在网络上传输或者持久化存储。


因此字节流本质上就是对二进制数据的抽象。通过使用字节流,我们可以方便地读写二进制数据,并且可以将Java对象序列化为字节流进行传输或者存储。


HOW 如何进行序列化

Java实现序列化有两种方式:实现 Serializable 接口和实现 Externalizable 接口


实现 Serializable 接口是比较常见的方式,它是 Java 提供的一个简单易用的序列化机制。通过实现 Serializable 接口,Java 对象的序列化和反序列化过程会被自动处理,无需进行手动实现。这种方式比较简单,适合对序列化过程不需要过多控制的场景。


而实现 Externalizable 接口需要手动实现对象的序列化和反序列化过程,包括 writeExternal() 和 readExternal() 两个方法。这种方式相对于实现 Serializable 接口,提供了更多的控制,可以更加灵活地处理对象的序列化和反序列化过程,但需要更多的代码实现。适合对序列化过程有一定控制需求的场景。


实现Serializable 接口的序列化和反序列化代码示例

业务场景是将java对象通过实现Serializable进行序列化将java对象存储在磁盘中。再通过反序列化将磁盘中的数据创建成java对象。

import java.io.*;
public class SerializeExample  implements Serializable{
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    public SerializeExample(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /**
     * @description:进行序列化
     * @author: wangwei
     * @date: 2023/4/15 9:13
     * @param: []
     * @return: void
     **/
    public void serialize() {
        try {
            //创建生成example.ser文件的路劲
            File file = new File("src\\main\\java","example.ser");
            //创建一个FileOutputStream对象制定将数据写入到example.sex文件中。这个过程称为对象的持久化。
            FileOutputStream fileOut = new FileOutputStream(file);
            //创建了一个ObjectOutputStream对象实现将Java对象序列化后写入到文件中
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            /*
            *第1步将当前对象序列化并写入输出流中,第2步和第3步是关闭输出流和文件输出流,
            * 以确保对象已经被完全写入文件中。如果不关闭输出流和文件输出流,那么对象可能没有被完全写入文件中,
            * 或者文件可能处于不一致的状态。因此,关闭输出流和文件输出流是一个良好的编程习惯,
            * 可以避免一些潜在的问题。
            */
            //将当前对象序列化并写入输出流中
            out.writeObject(this);
            //关闭输出流
            out.close();
            //文件输出流
            fileOut.close();
            System.out.println("Serialized data is saved in example.ser");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void deserialize() throws IOException, ClassNotFoundException {
        File file = new File("src\\main\\java","example.ser");
        // 反序列化
        FileInputStream fis = new FileInputStream(file);
        ObjectInputStream ois = new ObjectInputStream(fis);
        SerializeExample p = (SerializeExample)ois.readObject();
        ois.close();
        fis.close();
        System.out.println(p.name); // Alice
        System.out.println(p.age); // 20
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        SerializeExample example = new SerializeExample("John", 30);
        example.serialize();
        example.deserialize();
    }
}

实现效果

9c221fc215724cb781999777d1a61838.png


如果对于java对象中的一些属性和方法不想进行序列化有哪些方式。

1.被static修饰的字段和方法不会被序列化

2.被transient修饰的字段和方法不会被序列化

被 static 修饰的字段和方法不会被序列化,因为它们是属于类的而不是属于对象的。在序列化的过程中,Java 会将对象的状态序列化,而静态字段和方法是属于类的,不会保存在对象的状态中,因此不会被序列化。在反序列化的过程中,静态字段和方法也不会被还原。


被transient修饰的字段和方法在序列化的过程中会被忽略,从而不会被进行序列化。


通过这两种方式,如何我们不想java对象中的某些比较隐私相关的字段不被序列化,这里不做演示,感兴趣的可以进行实操。


实现Serializable的类中为什么需要private static final long serialVersionUID = 1L?

在实现Serializable接口的Java类中,需要声明一个私有静态常量serialVersionUID,该值是用来确定对象序列化版本的唯一标识符。它可以保证在序列化和反序列化时,不同的类版本之间不会发生不兼容性的问题。


如果不显式地声明serialVersionUID,在类结构被修改后,重新编译后的类的serialVersionUID可能会发生改变,从而导致反序列化时出现InvalidClassException异常。


serialVersionUID的值有什么要求吗?

serialVersionUID是通过一个64位的哈希算法来计算的,因此它的值是一个long型的数字。serialVersionUID的值没有特定的要求,只需要保证每个序列化版本的唯一标识符是不同的即可。通常情况下,建议将serialVersionUID设置为一个固定的值,以便在反序列化时可以正确地匹配版本。


显示声明了serialVersionUID后,如果类的实例字段被更改或添加或删除,serialVersionUID仍然不会发生改变。


serialVersionUID的作用是标识序列化对象的版本,用于在反序列化时验证版本的一致性,因此如果类的实例字段被更改或添加或删除,但是序列化对象的版本并未改变,则在反序列化时仍然可以成功。但是如果类的实例字段被更改或添加或删除,而序列化对象的版本已经改变,那么在反序列化时就会抛出InvalidClassException异常。因此,为了避免出现这种情况,建议在类中显式声明serialVersionUID,并且不要轻易更改它的值。


总结

博主整理和总结的关于Java序列化的知识还是很片面,算是一个阶段性总结,关于Java序列化还需要对计算机网络、远程调用、ORM等等理解更深入才能对Java序列化有更全面的理解。


目录
相关文章
|
2天前
|
存储 Java 数据库
|
2天前
|
存储 算法 Java
从零开始学习 Java:简单易懂的入门指南之IO序列化、打印流、压缩流(三十三)
从零开始学习 Java:简单易懂的入门指南之IO序列化、打印流、压缩流(三十三)
|
2天前
|
存储 安全 Java
Java一分钟之-Java序列化与反序列化
【5月更文挑战第14天】Java序列化用于将对象转换为字节流,便于存储和网络传输。实现`Serializable`接口使类可被序列化,但可能引发隐私泄露、版本兼容性和性能问题。要避免这些问题,可使用`transient`关键字、控制`serialVersionUID`及考虑使用安全的序列化库。示例代码展示了如何序列化和反序列化对象,强调了循环引用和未实现`Serializable`的错误。理解并妥善处理这些要点对优化代码至关重要。
14 1
|
2天前
|
分布式计算 Java 大数据
IO流【Java对象的序列化和反序列化、File类在IO中的作用、装饰器模式构建IO流体系、Apache commons-io工具包的使用】(四)-全面详解(学习总结---从入门到深化)
IO流【Java对象的序列化和反序列化、File类在IO中的作用、装饰器模式构建IO流体系、Apache commons-io工具包的使用】(四)-全面详解(学习总结---从入门到深化)
55 0
|
2天前
|
存储 Java 测试技术
滚雪球学Java(22):序列化和反序列化
【4月更文挑战第11天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
33 1
滚雪球学Java(22):序列化和反序列化
|
2天前
|
SQL 存储 安全
每日一道面试题:Java中序列化与反序列化
每日一道面试题:Java中序列化与反序列化
13 0
|
2天前
|
存储 Java
Java输入输出:解释一下序列化和反序列化。
Java中的序列化和反序列化是将对象转换为字节流和反之的过程。ObjectOutputStream用于序列化,ObjectInputStream则用于反序列化。示例展示了如何创建一个实现Serializable接口的Person类,并将其序列化到文件,然后从文件反序列化回Person对象。
28 5
|
2天前
|
存储 Java Maven
java序列化
java序列化
|
2天前
|
存储 缓存 JSON
什么是Java序列化,它有哪些重要性
什么是Java序列化,它有哪些重要性
|
2天前
|
存储 自然语言处理 Java
java缓冲流、转换流、序列化流、打印流
java缓冲流、转换流、序列化流、打印流介绍

热门文章

最新文章