boxmoe_header_banner_img

Hello! 欢迎来到悠悠畅享网!

文章导读

Java中对象序列化和反序列化方法


avatar
作者 2025年9月18日 9

Java通过实现Serializable接口实现对象序列化与反序列化,使用ObjectOutputStream和ObjectInputStream进行读写操作,推荐显式声明serialVersionUID以确保版本兼容性;transient关键字可标记不参与序列化的字段,用于保护敏感数据;通过自定义writeObject和readObject方法能控制序列化过程,实现加密等逻辑;但反序列化存在安全风险,如任意代码执行漏洞,需通过过滤类、避免序列化敏感信息等方式防范。

Java中对象序列化和反序列化方法

Java中对象序列化和反序列化,简单来说,就是把Java对象转换成字节流,以及把字节流恢复成Java对象的过程。这对于持久化对象状态,或者在网络上传输对象非常有用。

序列化:将Java对象转换为字节流。 反序列化:将字节流转换回Java对象。

序列化和反序列化在Java中是如何实现的?

要让一个Java对象能够被序列化,需要实现

java.io.Serializable

接口。这个接口是一个标记接口,没有任何方法需要实现,它的作用就是告诉jvm,这个类的对象是可以被序列化的。

import java.io.*;  public class MyObject implements Serializable {     private static final long serialVersionUID = 1L; // 推荐显式声明     private String name;     private int age;      public MyObject(String name, int age) {         this.name = name;         this.age = age;     }      public String getName() {         return name;     }      public int getAge() {         return age;     }      public static void main(String[] args) {         MyObject obj = new MyObject("Alice", 30);          // 序列化         try (FileOutputStream fileOut = new FileOutputStream("myobject.ser");              ObjectOutputStream out = new ObjectOutputStream(fileOut)) {             out.writeObject(obj);             System.out.println("Serialized data is saved in myobject.ser");         } catch (IOException i) {             i.printStackTrace();         }          // 反序列化         try (FileInputStream fileIn = new FileInputStream("myobject.ser");              ObjectInputStream in = new ObjectInputStream(fileIn)) {             MyObject obj2 = (MyObject) in.readObject();             System.out.println("Deserialized Object: Name = " + obj2.getName() + ", Age = " + obj2.getAge());         } catch (IOException i) {             i.printStackTrace();         } catch (ClassNotFoundException c) {             System.out.println("MyObject class not found");             c.printStackTrace();         }     } }

这段代码展示了如何将一个

MyObject

对象序列化到文件

myobject.ser

,然后再从该文件中反序列化出来。 需要注意的是,

serialVersionUID

的作用。 它是用来在反序列化时验证类的版本一致性的。 如果类的结构发生了改变(比如增加了字段),而

serialVersionUID

没有改变,反序列化可能会失败。 所以,推荐显式地声明

serialVersionUID

立即学习Java免费学习笔记(深入)”;

transient 关键字有什么用?

有时候,我们不希望某个字段被序列化。 例如,一个密码字段,或者一个缓存对象。 可以使用

transient

关键字来标记这些字段。

import java.io.*;  public class MyObject implements Serializable {     private static final long serialVersionUID = 1L;     private String name;     private transient String password; // 不会被序列化      public MyObject(String name, String password) {         this.name = name;         this.password = password;     }      // ... }

当对象被序列化时,

password

字段的值会被忽略。 在反序列化后,

password

字段的值会是

(对于对象引用) 或默认值 (对于基本类型)。 这是一个保护敏感数据的好方法。

自定义序列化和反序列化

Java中对象序列化和反序列化方法

OmniAudio

OmniAudio 是一款通过 AI 支持将网页、Word 文档、Gmail 内容、文本片段、视频音频文件都转换为音频播客,并生成可在常见 Podcast ap

Java中对象序列化和反序列化方法68

查看详情 Java中对象序列化和反序列化方法

Java 提供了自定义序列化和反序列化的机制,通过实现

writeObject

readObject

方法。 这允许你控制序列化和反序列化的过程,例如,加密敏感数据,或者处理复杂的对象关系。

import java.io.*;  public class MyObject implements Serializable {     private static final long serialVersionUID = 1L;     private String name;     private transient String password;      public MyObject(String name, String password) {         this.name = name;         this.password = password;     }      private void writeObject(ObjectOutputStream out) throws IOException {         // 自定义序列化逻辑         out.defaultWriteObject(); // 先序列化非 transient 字段         // 加密 password         String encryptedPassword = encrypt(password);         out.writeObject(encryptedPassword);     }      private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {         // 自定义反序列化逻辑         in.defaultReadObject(); // 先反序列化非 transient 字段         // 解密 password         String encryptedPassword = (String) in.readObject();         this.password = decrypt(encryptedPassword);     }      private String encrypt(String password) {         // 简单的加密示例,实际应用中需要更强的加密算法         return new StringBuilder(password).reverse().toString();     }      private String decrypt(String encryptedPassword) {         // 简单的解密示例         return new StringBuilder(encryptedPassword).reverse().toString();     }      // ... }

在这个例子中,

writeObject

方法在序列化时加密了

password

字段,

readObject

方法在反序列化时解密了

password

字段。 注意

defaultWriteObject

defaultReadObject

方法,它们用于序列化和反序列化非

transient

字段。

序列化和反序列化有什么安全风险?

反序列化漏洞是Java中一个常见的安全问题。 如果攻击者能够控制序列化的数据,他们可以构造恶意对象,导致任意代码执行。 例如,攻击者可以构造一个包含恶意命令的对象,当这个对象被反序列化时,恶意命令就会被执行。

为了避免反序列化漏洞,可以采取以下措施:

  • 避免序列化敏感数据。
  • 使用安全的序列化框架,例如 Kryo。
  • 使用对象过滤,限制可以被反序列化的类。
  • 禁用不必要的反序列化功能。

总而言之,Java的序列化和反序列化机制非常强大,但也需要谨慎使用,特别是涉及到安全问题时。



评论(已关闭)

评论已关闭