🎬 HoRain 云小助手个人主页

⛺️生活的理想,就是为了理想的生活!


⛳️ 推荐

前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。

目录

⛳️ 推荐

📊 一、核心概览

🛠️ 二、如何使用

1. 使类可序列化

2. 序列化对象(写入字节流)

3. 反序列化对象(从字节流读取)

⚠️ 三、注意事项与最佳实践

💡 四、常见应用场景

🔄 五、序列化过程示意图


Java 对象序列化流是其 I/O 系统的重要组成部分,它允许将对象转换为字节流以便存储或传输,并在需要时重新还原。下面我将为你详细解析其核心概念、使用方法及注意事项。

📊 一、核心概览

​核心概念​

​说明​

​关键类/关键字​

​序列化​

将 ​​Java 对象​​转换为​​字节序列​​的过程,用于网络传输或持久化存储

ObjectOutputStream

​反序列化​

将​​字节序列​​恢复为 ​​Java 对象​​的过程

ObjectInputStream

​序列化条件​

对象的类必须实现 java.io.Serializable接口(这是一个​​标记接口​​,无任何方法)

implements Serializable

​版本控制​

使用 serialVersionUID来验证序列化对象的发送者和接收者是否为同一个类版本,防止因类定义变更导致反序列化失败

private static final long serialVersionUID = ...L;

​字段控制​

使用 transient关键字修饰的字段将​​不被序列化​​;​​静态字段​​(static)属于类级别,也​​不会​​被序列化

transient, static

​应用场景​

网络传输(如 RPC)、对象持久化(保存到文件或数据库)、会话复制(如 Tomcat Session 复制)、缓存机制

🛠️ 二、如何使用

1. 使类可序列化

若要序列化一个对象,其所属类必须实现 Serializable接口。建议显式声明 serialVersionUID

import java.io.Serializable;

public class Person implements Serializable {
    // 显式声明序列化版本UID
    private static final long serialVersionUID = 1L; 
    
    private String name;
    private int age;
    private transient String password; // 使用 transient 关键字,此字段不会被序列化

    // 构造方法、getter 和 setter...
    public Person(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", password='" + password + "'}";
    }
}

citation:4]

2. 序列化对象(写入字节流)

使用 ObjectOutputStream将对象序列化并写入文件(或网络等)。

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class SerializeDemo {
    public static void main(String[] args) {
        Person person = new Person("Alice", 30, "secret123");
        
        // 使用 try-with-resources 确保流关闭
        try (FileOutputStream fileOut = new FileOutputStream("person.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
             
            out.writeObject(person); // 执行序列化
            System.out.println("Serialized data is saved in person.ser");
        } catch (IOException i) {
            i.printStackTrace();
        }
    }
}

citation:4]

3. 反序列化对象(从字节流读取)

使用 ObjectInputStream从文件中读取字节流并反序列化为对象。

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class DeserializeDemo {
    public static void main(String[] args) {
        Person person = null;
        
        try (FileInputStream fileIn = new FileInputStream("person.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn)) {
             
            person = (Person) in.readObject(); // 执行反序列化,需要强制类型转换
        } catch (IOException i) {
            i.printStackTrace();
            return;
        } catch (ClassNotFoundException c) {
            System.out.println("Person class not found");
            c.printStackTrace();
            return;
        }
        
        System.out.println("Deserialized Person...");
        System.out.println(person); 
        // 输出如:Person{name='Alice', age=30, password='null'} (password 为 transient 故为 null)
    }
}

citation:4]

⚠️ 三、注意事项与最佳实践

  1. ​谨慎序列化敏感信息​

    使用 transient关键字防止敏感字段(如密码)被序列化,或在序列化前进行加密。

  2. ​显式声明 serialVersionUID

    强烈建议显式声明 serialVersionUID。若未显式声明,JVM 会根据类结构自动生成一个。一旦类发生变化(如增删字段),自动生成的 UID 就会改变,导致反序列化时抛出 InvalidClassException

    private static final long serialVersionUID = 123456789L; // 自定义一个固定值
  3. ​理解 transientstatic

    • transient修饰的字段:​​不参与​​序列化,反序列后通常为 null(或基本类型的默认值)。

    • static修饰的字段:属于类而非对象,​​不会被序列化​​。

  4. ​序列化性能与安全​

    • ​性能​​:Java 原生序列化会产生较大字节流且效率相对较低。在高性能或跨语言场景下,可考虑 ​​JSON​​(如 Jackson)、​​Protocol Buffers​​ (Protobuf) 等替代方案。

    • ​安全​​:​​切勿反序列化来自不可信来源的字节流​​,这可能引发严重安全漏洞(如反序列化攻击)。

  5. ​序列化对象图​

    序列化一个对象时,其引用的其他对象(除非标记为 transient)也会被递归序列化。所有这些引用对象都必须实现 Serializable接口,否则会抛出 NotSerializableException

💡 四、常见应用场景

  • ​对象持久化​​:将对象状态保存到文件或数据库中,以便下次程序运行时恢复。

  • ​网络传输​​:在 RPC(远程过程调用)、Java RMI 或自定义网络协议中传输对象。

  • ​分布式会话​​:在集群环境中,将 Web 会话(HttpSession)序列化后存入 Redis 等中间件,实现会话共享。

  • ​深度拷贝​​:通过序列化再反序列化来实现对象的深度拷贝(Deep Copy)。

🔄 五、序列化过程示意图

graph LR
A[Java Object] -- ObjectOutputStream / writeObject --> B[Byte Stream<br>序列化]
B -- 保存至文件或网络传输 --> C[File or Network]
C -- ObjectInputStream / readObject --> D[Java Object<br>反序列化]

希望这份详细的解析能帮助你全面理解 Java 对象序列化流。

❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐