You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用defaultWriteObject时抛出NotActiveException问题求助

搞定Java序列化中writeObject抛出NotActiveException的问题

嘿,我来帮你捋清楚这个问题——你遇到的NotActiveException,大概率是因为你没按Java序列化的规矩来调用writeObject方法,比如自己手动直接调用了它,而不是让ObjectOutputStream来自动触发这个回调。Java的序列化机制有严格的流程,writeObject必须由序列化框架主动调用,你自己直接调就会触发这个异常。

先搞懂为啥会抛这个异常

举个反例:如果你在代码里写了bankAccount.writeObject(out);,而不是正确的out.writeObject(bankAccount);,那就是跳过了序列化框架的流程,直接调用了自定义的writeObject,这时候defaultWriteObject()就找不到合适的序列化上下文,自然就抛出NotActiveException了。

针对你的场景(加密transient的password)的正确实现

既然password是transient字段,要自己处理加密解密,那我们得按序列化框架的要求来写:

1. 正确的Account类实现

import java.io.*;

class Account implements Serializable {
    private String name;
    private long accountNumber;
    private transient String password; // 瞬态字段,框架不会自动序列化它
    private double balance;

    public Account(String name, long accountNumber, String password, double balance) {
        this.name = name;
        this.accountNumber = accountNumber;
        this.password = password;
        this.balance = balance;
    }

    // 这个方法必须是private!只能由序列化框架自动调用
    private void writeObject(ObjectOutputStream out) throws IOException {
        // 先让框架处理非transient的字段
        out.defaultWriteObject();
        // 手动加密password然后序列化
        String encryptedPwd = encrypt(password); // 替换成你实际的加密逻辑
        out.writeObject(encryptedPwd);
    }

    // 对应的反序列化方法,同样要private
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        // 先让框架恢复非transient字段
        in.defaultReadObject();
        // 读取加密后的密码并解密
        String encryptedPwd = (String) in.readObject();
        this.password = decrypt(encryptedPwd); // 替换成你实际的解密逻辑
    }

    // 示例加密方法,你换成自己的加密实现就行
    private String encrypt(String plainText) {
        // 这里只是简单反转,实际要用比如AES之类的加密算法
        return new StringBuilder(plainText).reverse().toString();
    }

    // 示例解密方法
    private String decrypt(String encryptedText) {
        return new StringBuilder(encryptedText).reverse().toString();
    }

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                ", accountNumber=" + accountNumber +
                ", password='" + password + '\'' +
                ", balance=" + balance +
                '}';
    }
}

2. 正确的序列化/反序列化调用代码

public class SerializationDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 序列化操作
        Account bankAccount = new Account("Person", 123456789, "Pa55word", 900);
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("account.ser"))) {
            out.writeObject(bankAccount); // 关键!让框架触发writeObject
            System.out.println("序列化完成:" + bankAccount);
        }

        // 反序列化操作
        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("account.ser"))) {
            Account restoredAccount = (Account) in.readObject();
            System.out.println("反序列化完成:" + restoredAccount);
        }
    }
}

几个必须注意的点

  • 绝对不能手动调用writeObject/readObject:这俩是框架的回调方法,只能让ObjectOutputStream/ObjectInputStream来调用,自己直接调必出问题。
  • 方法必须是private修饰:这是Java序列化机制的硬性要求,确保只有框架能访问,避免你不小心误调用。
  • defaultWriteObject的顺序:一定要先调用它处理默认字段,再处理你自己的自定义序列化逻辑,反序列化同理,先调用defaultReadObject再处理密码解密。

内容的提问来源于stack exchange,提问作者MISHA TSIRLIN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:35:24