首页 > 编程语言 >Java序列化

Java序列化

时间:2024-12-16 17:28:57浏览次数:6  
标签:java 字节 对象 Person Java 序列化

Java序列化

简单来说:

序列化是将对象的状态信息转换为可以存储或传输的形式(如字节序列)的过程。在 Java 中,通过序列化可以把一个对象保存到文件、通过网络传输到其他地方或者存储到数据库等。最直接的原因就是某些场景下需要使用这种数据状态,像网络中不能传输数据,某些存储场景。在java中常见使用,就是实现Serializable接口,而不想被序列化的字段处理方法使用transient关键字就可以了

推荐文章:为什么网络中不能直接传输数据

为什么在网络中不能直接传输数据_在网络通信中,除了文本和二进制数据,其他的数据都无法传输-CSDN博客

1. Java 中序列化的定义与作用
  • 定义:序列化是将对象的状态信息转换为可以存储或传输的形式(如字节序列)的过程。在 Java 中,通过序列化可以把一个对象保存到文件、通过网络传输到其他地方或者存储到数据库等。例如,在分布式系统中,一个对象可能需要从一个节点传输到另一个节点,此时就需要将对象序列化。

  • 原理:Java 序列化机制会自动处理对象的成员变量。当对一个对象进行序列化时,Java 会递归地将对象的非静态和非瞬态(transient)成员变量转换为字节序列。这些字节序列包含了对象的类型信息和成员变量的值等内容。例如,对于一个包含姓名和年龄的Person类对象,序列化后字节序列会包含表示Person类的信息以及姓名和年龄的值的信息。

  • 应用场景:

    • 持久化存储:将对象保存到文件系统中,以便以后可以恢复对象的状态。例如,游戏中的玩家存档,玩家的角色信息(等级、装备等)可以通过序列化存储到本地文件,下次游戏时再读取并恢复。

    • 网络传输:在分布式应用或远程调用(如 Java RMI)中,对象需要在不同的主机之间传输。例如,在一个基于微服务架构的电商系统中,订单信息对象可能需要从订单服务传输到库存服务,这就需要对订单信息对象进行序列化。

2. 不想被序列化的字段处理方法(使用transient关键字)
  • transient关键字的作用:当一个成员变量被声明为transient时,在序列化过程中这个变量将不会被包含在序列化后的字节序列中。例如,对于一个包含密码字段的User类,如果不想将密码序列化(因为安全原因),可以将密码字段声明为transient

  • 示例代码:

     import java.io.Serializable;
     class Student implements Serializable {
         private String name;
         private transient int score;
         public Student(String name, int score) {
             this.name = name;
             this.score = score;
         }
         public String getName() {
             return name;
         }
         public int getScore() {
             return score;
         }
     }
    • 假设有一个Student类,其中有一个成绩字段不想被序列化。

      - 在这个例子中,`Student`类实现了`Serializable`接口,表示这个类的对象可以被序列化。`score`字段被声明为`transient`,所以当对`Student`对象进行序列化时,`score`字段的值不会被保存到序列化后的字节序列中。在反序列化时,`transient`字段会被初始化为默认值(对于基本类型,如`int`,默认值为0)。

3. 为什么使用序列化

对象持久化保存

  • 在很多应用场景中,需要将对象的状态长期保存下来。例如,在一个企业级的资源管理系统中,用户的配置信息、系统的状态快照等都需要保存到文件或者数据库中,以便在下次启动程序或者系统恢复时能够重新加载这些信息。序列化提供了一种简单有效的方式来将对象转换为字节序列,这样就可以方便地存储到磁盘上。如果没有序列化,要将复杂的对象存储起来会非常复杂,可能需要手动将每个属性的值逐个提取出来并按照特定的格式写入文件,而序列化机制自动完成了这个复杂的过程。

网络通信的需要

  • 网络确实不能直接传输像 Java 对象这种复杂的数据结构。网络通信协议通常是基于字节流或者消息包来传输数据的。当需要在不同的计算机系统或者进程之间传递对象时,就必须先将对象序列化。例如,在一个分布式的微服务架构中,一个服务需要调用另一个服务的方法并传递一些业务对象作为参数,这些对象必须被序列化后通过网络传输到目标服务,目标服务再将字节序列反序列化回对象,这样才能进行正常的业务处理。

跨平台和跨语言交互

  • 序列化后的字节序列可以在不同的平台和语言环境下进行传输和处理。有些序列化格式(如 JSON、XML)是跨语言兼容的。例如,一个 Java 服务可以将一个对象序列化为 JSON 格式的字节序列,这个字节序列可以被 Python 服务接收并反序列化,这样就实现了不同语言编写的服务之间的交互。这种跨平台和跨语言的特性使得序列化在分布式系统和异构系统集成中非常重要。

缓存系统的应用

  • 在缓存系统中,对象经常需要被存储和检索。序列化允许将对象以一种适合缓存存储的形式(如字节序列)存入缓存中。例如,在一个 Web 应用的缓存系统中,经常需要缓存一些复杂的业务对象(如用户信息、商品详情等),通过序列化可以方便地将这些对象存入像 Redis 这样的缓存中,当需要使用时再反序列化出来,提高了系统的性能和响应速度。

4. 怎么序列化
  1. 实现Serializable接口

    • 接口介绍:在 Java 中,要使一个类可序列化,首先要让这个类实现java.io.Serializable接口。这个接口是一个标记接口,没有任何方法需要实现,它的作用是告诉 Java 虚拟机(JVM)这个类的对象可以被序列化。例如,假设有一个简单的Person类,包含姓名和年龄两个属性:

       import java.io.Serializable;
       class Person implements Serializable {
           private String name;
           private int age;
           public Person(String name, int age) {
               this.name = name;
               this.age = age;
           }
           public String getName() {
               return name;
           }
           public int getAge() {
               return age;
           }
       }

    - **注意事项**:实现`Serializable`接口只是第一步,当类的结构发生变化(如添加或删除成员变量、修改成员变量的类型等)时,可能会影响序列化和反序列化的兼容性。为了更好地控制序列化过程,还可以定义一个`serialVersionUID`(序列化版本号)。这个版本号是一个`long`型的常量,用于标识类的序列化版本。如果在反序列化时,类的`serialVersionUID`与序列化时的版本号不一致,可能会导致`InvalidClassException`异常。例如,可以在`Person`类中添加版本号:
      ```java
      import java.io.Serializable;
      class Person implements Serializable {
          private static final long serialVersionUID = 1L;
          // 后续代码同前
      }

  1. 使用ObjectOutputStream进行序列化

    • 基本步骤:要将一个对象序列化到文件中,可以使用ObjectOutputStream类。首先创建一个文件输出流(FileOutputStream),然后将其包装成ObjectOutputStream

      。接着,使用ObjectOutputStream的writeObject方法将对象写入到输出流中。例如,将Person对象序列化到文件:

       import java.io.FileOutputStream;
       import java.io.ObjectOutputStream;
       import java.io.IOException;
       public class SerializeExample {
           public static void main(String[] args) {
               try {
                   Person person = new Person("Alice", 30);
                   FileOutputStream fileOut = new FileOutputStream("person.ser");
                   ObjectOutputStream out = new ObjectOutputStream(fileOut);
                   out.writeObject(person);
                   out.close();
                   fileOut.close();
                   System.out.println("对象已序列化到文件");
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
    - **工作原理**:`ObjectOutputStream`在序列化对象时,会递归地处理对象的非静态和非瞬态(`transient`)成员变量。它会将对象的类型信息和成员变量的值按照特定的格式转换为字节序列,并写入到输出流中。如果对象的成员变量也是可序列化的对象,`ObjectOutputStream`会同样地对这些成员变量进行序列化。
 ​
 3. **从序列化数据中恢复对象(反序列化)**
    - **基本步骤**:使用`ObjectInputStream`类从序列化的数据中恢复对象。首先创建一个文件输入流(`FileInputStream`),然后将其包装成`ObjectInputStream`。接着,使用`ObjectInputStream`的`readObject`方法从输入流中读取对象。例如,从之前序列化的文件中读取`Person`对象:
      ```java
      import java.io.FileInputStream;
      import java.io.ObjectInputStream;
      import java.io.IOException;
      public class DeserializeExample {
          public static void main(String[] args) {
              try {
                  FileInputStream fileIn = new FileInputStream("person.ser");
                  ObjectInputStream in = new ObjectInputStream(fileIn);
                  Person person = (Person) in.readObject();
                  in.close();
                  fileIn.close();
                  System.out.println("姓名:" + person.getName() + ",年龄:" + person.getAge());
              } catch (IOException | ClassNotFoundException e) {
                  e.printStackTrace();
              }
          }
      }

  • 工作原理ObjectInputStream会读取字节序列,并根据其中包含的类型信息和成员变量的值,重新构建对象。它会按照序列化时的顺序和规则,将字节序列转换回对象的状态。如果在反序列化过程中遇到类的定义发生变化(如添加或删除成员变量),可能需要特殊的处理来确保对象能够正确地恢复。

标签:java,字节,对象,Person,Java,序列化
From: https://blog.csdn.net/qq_62097431/article/details/144513752

相关文章

  • java常见的集合框架
    常见的集合框架JAVA的集合框架可以分成两类。Collection,主要有List、vector、set、queueList代表有序,可重复的集合,像动态数组ArrayList和链表LinkedListSet代表无序不可重复的集合。像HashSet、TreeSetQueue代表队列,像双端队列ArrayQueue,优先队列PriorityQueueMap,代......
  • 【蓝队】HW中盛行的Java内存马,如何全面检测?
    一、背景1.1Java内存马是什么?内存马是一种仅在内存中运行、没有文件落地的恶意程序,因此具有较强的隐蔽性,能够避开常规的基于文件系统的检测。Java内存马是针对Java语言的内存马,它利用Java语言的动态特性,如类加载机制、动态代理和反射技术等,在Java应用的内存中注入恶意代码,从而......
  • 【华为OD-E卷-ai面板识别 100分(python、java、c++、js、c)】
    【华为OD-E卷-ai面板识别100分(python、java、c++、js、c)】题目AI识别到面板上有N(1≤N≤100)个指示灯,灯大小一样,任意两个之间无重叠。由于AI识别误差,每次别到的指示灯位置可能有差异,以4个坐标值描述AI识别的指示灯的大小和位置(左上角x1,y1,右下角x2,y2),请输出先行后......
  • JavaScript的对象相关概念
    当然可以,以下是将上述对话整理成Markdown格式的内容:JavaScript面向对象编程相关概念原型链(PrototypeChain)原型链是JavaScript中查找对象属性和方法的机制。它从对象的__proto__属性开始,向上逐层搜索直到找到属性或方法或到达Object.prototype。原型(Prototype)每个Java......
  • Java 基础学习路线
    一、环境搭建与入门(1-2周)安装Java开发工具包(JDK),配置环境变量,确保能够在命令行中正常运行Java命令。选择一款集成开发环境(IDE),如Eclipse或IntelliJIDEA,熟悉其基本操作,包括创建项目、编写代码、调试程序等。学习Java的基本语法,包括变量、数据类型(基本数据类型如in......
  • Java -chapter3控制语句
    1.switch语句switch(choice){case1->...case2->...case3->...case4->...default->System.out.println("Badinput");}case的类型charbyteshortint枚举enum字符串多个变量可用,分隔例:Stringinput=...;switch(inpu......
  • Java程序员面试1000问,花点耐心看完offer拿到手软
    前言:本文收集整理了各大厂常见面试题N道,你想要的这里都有内容涵盖:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、SpringBoot、SpringCloud、RabbitMQ、Kafka、Linux等技术栈,希望大家都能找到适合自己的公司,开开心心的撸代码。目录:......
  • 2025春招Java 面试必刷的1200 道Java大厂面试真题(含答案解析)
    2025春招即将来临,很多同学会问Java面试八股文有必要背吗?我的回答是:很有必要。你可以讨厌这种模式,但你一定要去背,因为不背你就进不了大厂。国内的互联网面试,恐怕是现存的、最接近科举考试的制度。而且,我国的八股文确实是独树一帜。以美国为例,北美工程师面试比较重视算法(Cod......
  • java中RSA加密解密的使用
    作为常用的非对称加密算法,本篇文章大致记录一下,在java代码中如何生成RSA的密钥对以及加密解密的使用。1、生成密钥对publicclassRSAUtils{//填充方式publicstaticfinalStringRSA_ALGORITHM_NOPADDING="RSA";publicstaticfinalStringRSA_ALGORITH......
  • 2024年金九银十版 Java 面试八股文教程,涵盖 25 大专题
    内卷可以说是2024年最火的一个词了。LZ在很多程序员网站看到很多Java程序员的2024年度总结都是:Java越来越卷了(手动狗头),2024年是被卷的一年。前有几百万毕业生虎视眈眈,后有在职人员带头“摸鱼”占着坑位,加上现在的行情让很多公司倒闭,市面上根本没那么多就业岗位。自然而......