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序列化有更全面的理解。


目录
相关文章
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
29天前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
71 5
|
1月前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
25 3
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
3月前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
2月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
2月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。
|
2月前
|
消息中间件 存储 Java
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
47 3
|
2月前
|
分布式计算 资源调度 Hadoop
Hadoop-10-HDFS集群 Java实现MapReduce WordCount计算 Hadoop序列化 编写Mapper和Reducer和Driver 附带POM 详细代码 图文等内容
Hadoop-10-HDFS集群 Java实现MapReduce WordCount计算 Hadoop序列化 编写Mapper和Reducer和Driver 附带POM 详细代码 图文等内容
99 3
|
2月前
|
Java 数据库 对象存储
Java 序列化详解
本文详细解析了Java序列化的概念与应用。通过具体实例,深入探讨了其在对象存储和传输中的作用及实现方法,帮助读者理解如何有效利用这一特性来简化数据交换,并对其实现机制有了更深入的认识。