首页 > 编程语言 >Java中的序列化与反序列化

Java中的序列化与反序列化

时间:2024-07-15 21:54:21浏览次数:16  
标签:Java 变量 对象 格式 序列化 String

序列化与反序列化的定义

序列化(Serialization)与反序列化(Deserialization)是编程中常见的两个概念,它们主要涉及到将数据结构或对象状态转换为可以存储或传输的格式,以及将存储或传输的格式转换回原始的数据结构或对象状态的过程。
这两个过程在数据持久化、网络通信、对象深拷贝等多个场景中发挥着重要作用。

序列化(Serialization)

序列化是指将数据结构或对象状态转换成可以存储或传输的格式的过程。这个格式通常是平台无关的,比如JSON、XML、二进制格式等,以便可以在不同的系统或环境中进行交换。序列化后的数据可以存储在文件中,或者通过网络发送给其他系统。

为什么需要序列化?

  • 数据持久化:将对象状态保存到文件中,以便在程序关闭或系统重启后能够重新加载这些数据。
  • 网络传输:在网络通信中,数据需要在客户端和服务器之间传输,序列化可以将对象转换成字节流,便于在网络上传输。
  • 对象深拷贝:通过序列化一个对象,然后立即进行反序列化,可以实现对象的深拷贝。

反序列化(Deserialization)

反序列化是序列化的逆过程,即将序列化后的数据(如JSON、XML、二进制格式等)转换回原始的数据结构或对象状态。这个过程允许程序在需要时重新构建对象,并使用其原始数据。

为什么需要反序列化?

  • 数据恢复:在程序启动时,从文件中读取序列化后的数据,反序列化成对象,以恢复程序运行前的状态。
  • 数据接收:在网络通信中,接收到的序列化数据需要被反序列化成对象,以便在本地系统中使用。

Java的序列化

Java序列化是指将Java对象的状态转换为可以保存或传输的格式的过程。Java提供了多种序列化方式,以满足不同的需求和场景。以下是Java序列化的几种主要方式:

1. 实现Serializable接口

  • 特点:这是Java默认的序列化方式,通过实现java.io.Serializable接口来标记一个类可以被序列化。这种序列化方式是隐式的,会自动序列化所有非static和transient关键字修饰的成员变量。
  • 使用场景:适用于大多数需要序列化的场景,特别是当对象的状态需要被持久化或在网络间传输时。

2. 实现Externalizable接口

  • 特点:与Serializable接口类似,但Externalizable接口提供了更高的灵活性。实现该接口的类必须手动实现writeExternal()和readExternal()方法,以控制序列化和反序列化的过程。
  • 使用场景:适用于需要精确控制序列化过程的场景,比如只序列化对象的某些部分,或者需要对序列化数据进行加密等。

3. 使用JSON序列化库

  • 常用库:如Jackson、Gson等。
  • 特点:将对象转换为JSON格式的字符串进行序列化,可以跨语言、跨平台进行数据交换。JSON格式易于阅读和编写,也易于机器解析和生成。
  • 使用场景:适用于需要与其他语言或系统交互的场景,或者当对象需要被存储为文本格式时。

4. 使用XML序列化库

  • 常用库:如JAXB、XStream等。
  • 特点:将对象转换为XML格式的字符串进行序列化,同样可以跨语言、跨平台进行数据交换。XML格式具有良好的可扩展性和可读性。
  • 使用场景:适用于需要遵循特定XML标准的场景,或者当对象需要被存储为易于人类阅读的格式时。

5. 使用二进制序列化库

  • 常用库:如Protocol Buffers(protobuf)、Apache Thrift、Apache Avro等。
  • 特点:将对象序列化为二进制格式进行传输和存储,效率较高。这些库通常提供了丰富的数据结构和高效的编码解码算法。
  • 使用场景:适用于对性能要求较高的场景,比如需要频繁序列化和反序列化大量数据的系统。

6. 其他序列化方式

  • Hessian序列化:Hessian是一种通过网络传输和存储Java对象的二进制格式,可以跨语言、跨平台使用,效率较高。
  • Kryo序列化:Kryo是一种高性能的Java序列化库,序列化和反序列化速度都很快,但只能用于Java环境。

Java提供了多种序列化方式,每种方式都有其特点和适用场景。在实际应用中,可以根据具体需求和场景选择合适的方式进行Java对象的序列化。需要注意的是,除了Java默认的序列化方式外,其他方式通常需要引入相应的第三方库。


Java默认序列化与反序列化示例

我们先将一些Java的变量和一个Car对象序列化到 d盘的一个名为 data.dat 的文件中。

/**
 * ObjectOutputStream 的使用,完成数据的序列化
 * ObjectOutputStream 是序列化
 */
public class ObjectOutputStreamDemo {

    public static void main(String[] args) throws IOException {
        //序列化后,保存到文本格式不是纯文本txt,而是按照它的格式来保存
        String filePath = "d:\\data.dat";

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
        oos.writeInt(100);//int -> Integer(实现了Serializable)
        oos.writeBoolean(true);//boolean -> Boolean(实现了 Serializable)
        oos.writeChar('o');//char -> Character(实现了Serializable)
        oos.writeDouble(4.4);//double -> Double(实现了 Serializable)
        oos.writeUTF("对象输出流");//String (实现了Serializable)
        oos.writeObject(new Car("xiaomi su7","Pro","Gulf Blue","300,000"));
        oos.close();
        System.out.println("数据以序列化的形式保存完成");
        /*
        如果Car没有实现 Serializable接口,会报错如下:
        Exception in thread "main" java.io.NotSerializableException: org.example.io.demo.lession20.Car
        	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	        at org.example.io.demo.lession20.ObjectOutputStreamDemo.main(ObjectOutputStreamDemo.java:24)
         */
    }
}

@Data
class Car implements Serializable {
    private String name;
    private String type;
    private static String color ;
    private transient String price ;

    public Car(String name,String type,String color,String price){
        this.name = name;
        this.type = type;
        this.color = color;
        this.price = price;
    }
}

执行main方法后,会在d盘根目录下看到一个 data.dat的文件。

在这里插入图片描述
使用记事本打开,依稀可以看到点什么,但明显不是txt格式的文本。
在这里插入图片描述

下面我们将这个文件反序列化至程序中并打印出来:

/**
 * 读取序列化文件,并通过反序列化恢复数据
 * ObjectInputStream 是反序列化
 */
public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //指定反序列化的文件
        String filePath = "d:\\data.dat";
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
        //读取(即反序列化)的顺序需要和保存数据(即序列化)的顺序一致,否则会有异常
        System.out.println(ois.readInt());
        System.out.println(ois.readBoolean());
        System.out.println(ois.readChar());
        System.out.println(ois.readDouble());
        System.out.println(ois.readUTF());
        System.out.println(ois.readObject().toString());
        ois.close();
    }
}

输出结果为:

100
true
o
4.4
对象输出流
Car(name=xiaomi su7, type=Pro, price=null)


Java 序列化与反序列化注意事项:

  1. 读写顺序要一致。
  2. 序列化与反序列化对象要实现 Serializable 接口。
  3. 序列化中的类中,建议添加SerialVersionUID,为了提高版本的兼容性。
  4. 序列化对象时,默认将里面所有的属性都进行序列化,除了stati、transient 修饰的成员。
  5. 序列化对象时,要求里面属性的类型也需要实现序列化接口。
  6. 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也默认实现了序列化。

TIPS:statictransient 在序列化中的区别

static关键字

  • 定义:static关键字用于修饰类的成员变量和方法,使其成为类变量或类方法,而不是实例变量或实例方法。类变量属于类本身,而非类的任何特定实例。
  • 序列化行为:在序列化过程中,被static修饰的变量(即类变量)不会被序列化。这是因为static变量是类级别的,它们不属于任何特定的对象实例,而是由所有实例共享。因此,序列化一个对象时,不会包含其类变量的值,因为类变量的值在JVM中是全局的,与特定的序列化实例无关。
  • 反序列化影响:反序列化一个对象时,被static修饰的变量会保持其在JVM中的当前值,而不是从序列化数据中恢复。这是因为静态变量是全局的,不受单个对象实例的序列化/反序列化过程影响。

transient关键字

  • 定义:transient关键字用于修饰类的成员变量,以指示该变量在序列化时不应被序列化。
  • 序列化行为:当一个对象被序列化时,所有非transient修饰的成员变量都会被序列化,而transient修饰的变量则会被忽略。这意味着,在序列化后的数据中,不会包含任何被transient修饰的变量的值。
  • 反序列化影响:在反序列化过程中,被transient修饰的变量将不会被恢复其序列化前的值。相反,它们会被初始化为默认值(例如,数值类型的变量会被初始化为0或false,对象类型的变量会被初始化为null)。因此,开发者需要在反序列化后,根据需要手动为这些变量赋值。

二者对比表格

关键字定义序列化行为反序列化影响
static修饰类变量或类方法,属于类本身不被序列化保持JVM中的当前值
transient修饰成员变量,指示在序列化时忽略该变量被忽略,不被序列化被初始化为默认值

以上就是 Java中的序列化与反序列化 的全部内容,感谢阅读!

标签:Java,变量,对象,格式,序列化,String
From: https://blog.csdn.net/yuiezt/article/details/140449355

相关文章

  • Java进度1
    一、IDEA1、成功下载IDEA,学会如何建立项目、模块、包及类2、在IDEA中成功运行第一个代码,如下:二、算术运算符与转换1、算术运算符的认识(+-*/%)以及简单练习需要注意的是//整数计算只能得出整数//有小数参与计算得出的结果可能不精确,如下图得出:2、隐式转换:取值范围小......
  • Java语言程序设计——篇四(1)
    类和对象面向对象概述面向过程与面向对象面向对象基本概念面向对象的基本特征面向对象的优势及应用为对象定义类类的修饰符成员变量成员变量-修饰符构造方法⭐️成员方法成员方法-修饰符例题讲解⚠️理解栈和堆面向对象概述两种程序设计方法结构化程序设计,典型代表......
  • Java语言程序设计——篇四(2)
    类和对象方法设计定义和使用方法访问方法和修改方法方法的调用方法参数的传递✨方法重载✨构造方法(构造器)......
  • [深入理解Java虚拟机]线程
    状态转换Java语言定义了6种线程状态,在任意一个时间点中,一个线程只能有且只有其中的一种状态,并且可以通过特定的方法在不同状态之间转换。这6种状态分别是:新建(New):创建后尚未启动的线程处于这种状态,运行(Runnable):包括操作系统线程状态中的Running和Ready,也就是处于此状态......
  • javap和字节码
    javap字节码的基本信息publicclassTest{privateintage=10;publicintgetAge(){returnage;}}在class文件的同级目录下输入命令javap-v-pTest.class来查看一下输出的内容//字节码文件的位置Classfile/D:/Code/code/JavaCod......
  • Java——N以内累加求和
    2024/07/151.题目2.错误3.分析4.答案1.题目2.错误importjava.util.Scanner;publicclassMain{ publicstaticvoidmain(String[]args){ Scannerscanner=newScanner(System.in); intN=scanner.nextInt(); intsum=0; while(N<=1000){ for(......
  • 学习Java的第二周
    本该周六晚之前发表的第二次博客...因为自己也出了意外进了急诊拖到现在,先在这里致歉...黑马网课看了将近三十个课时了,目前感觉良好,越看越学越有兴趣。对于我这种0基础的小菜来说,初学时不应该追求深度,而应该去追求广度。从基础语法(方法、判断和循环、数组等)到面向对象,API、字符......
  • 基于Java+ Java Swing Mysql 实现的学生宿舍管理系统设计与实现
    一、前言介绍:1.1项目摘要随着高校招生规模的不断扩大,学生宿舍管理面临着越来越多的挑战。传统的学生宿舍管理方式往往依赖于人工记录、纸质档案和口头通知,这种方式不仅效率低下,而且容易出错,给宿舍管理带来了诸多不便。因此,开发一套高效、便捷、准确的学生宿舍管理系统成......
  • 基于Java+Ssm+Mysql实现的Java Web酒店管理项目系统设计与实现
    一、前言介绍:1.1项目摘要随着信息技术的快速发展和互联网的普及,传统酒店行业面临着转型升级的压力。为了提高酒店的经营管理水平,提升客户体验,酒店管理系统应运而生。酒店管理系统通过整合酒店内部资源,实现信息的快速传递和处理,为酒店提供了高效、便捷的管理手段。课题“......
  • JAVA之File操作
    目录File教程一、file基本操作创建File类对象2.File类中判断功能的方法3.file类的创建功能的方法4.File类中的遍历功能5.file类中常用的方法6.file中文件权限操作的方法File教程一、file基本操作创建File类对象/***创建File类对象*路径分......