ZetCode

Java NotActiveException 类

最后修改时间:2025 年 4 月 16 日

当序列化或反序列化未激活时,会抛出 java.io.NotActiveException。它通常发生在无效尝试使用 ObjectStreamClass 方法时。此异常表示序列化上下文使用不正确。

NotActiveException 扩展自 ObjectStreamException,是 Java 序列化机制的一部分。 当尝试在适当的序列化上下文之外执行操作时,它由 ObjectInputStream 和 ObjectOutputStream 抛出。这是一个已检查的异常。

NotActiveException 类概述

NotActiveException 标志着无效的序列化状态操作。 当在错误的时间调用 ObjectStreamClass 方法时,它通常会被抛出。 该异常有两个构造函数 - 默认构造函数和带有消息参数的构造函数。

public class NotActiveException extends ObjectStreamException {
    public NotActiveException();
    public NotActiveException(String reason);
}

上面的代码显示了 NotActiveException 的简单结构。除了标准异常功能之外,它还提供了最少的功能。第二个构造函数中的 reason 参数允许自定义错误消息。

基本的 NotActiveException 示例

此示例演示了当错误使用 ObjectStreamClass 方法时如何发生 NotActiveException。我们尝试在序列化上下文之外获取 serialVersionUID,这将触发异常。

Main.java
import java.io.NotActiveException;
import java.io.ObjectStreamClass;

public class Main {

    public static void main(String[] args) {
        try {
            // Attempt to get serialVersionUID outside serialization
            ObjectStreamClass osc = ObjectStreamClass.lookup(String.class);
            long serialVersionUID = osc.getSerialVersionUID();
            
            System.out.println("String class serialVersionUID: " + serialVersionUID);
        } catch (NotActiveException e) {
            System.err.println("Error: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

此代码尝试在没有正确序列化上下文的情况下获取 serialVersionUID。 NotActiveException 被抛出,因为我们不在活动序列化操作中。 异常表明 API 使用时序不正确。

序列化上下文示例

此示例展示了在实际序列化期间正确检索 serialVersionUID。我们创建了一个简单的可序列化类,并演示了正确的上下文使用。

Main.java
import java.io.*;

class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        // Proper serialization context
        ObjectStreamClass osc = ObjectStreamClass.lookup(Person.class);
        long suid = osc.getSerialVersionUID();
        System.out.println("SerialVersionUID in writeObject: " + suid);
        
        out.defaultWriteObject();
    }
}

public class Main {
    public static void main(String[] args) {
        Person p = new Person("John Doe", 30);
        
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            
            oos.writeObject(p);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例展示了在序列化期间正确检索 serialVersionUID。 writeObject 方法为 ObjectStreamClass 操作提供了适当的上下文。在这种有效场景中,不会发生 NotActiveException

无效的反序列化上下文

此示例演示了在不正确的反序列化尝试期间的 NotActiveException。我们尝试在适当的反序列化上下文之外使用 ObjectStreamClass 方法。

Main.java
import java.io.*;

public class Main {
    public static void main(String[] args) {
        try {
            // Attempt to use ObjectStreamClass outside deserialization
            ObjectStreamClass osc = ObjectStreamClass.lookup(String.class);
            String className = osc.getName();
            
            System.out.println("Class name: " + className);
            
            // This will throw NotActiveException
            ObjectStreamField[] fields = osc.getFields();
            System.out.println("Fields count: " + fields.length);
        } catch (NotActiveException e) {
            System.err.println("NotActiveException caught: " + e.getMessage());
        }
    }
}

代码尝试在没有活动反序列化的情况下获取字段信息。虽然 lookupgetName 可以工作,但 getFields 抛出 NotActiveException。这显示了 ObjectStreamClass 中依赖于上下文的方法行为。

自定义序列化示例

此示例演示了正确的自定义序列化,其中 ObjectStreamClass 方法可以正常工作。我们同时实现了 writeObject 和 readObject 方法。

Main.java
import java.io.*;

class Employee implements Serializable {
    private static final long serialVersionUID = 2L;
    private String name;
    private transient int salary;
    
    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        ObjectStreamClass osc = ObjectStreamClass.lookup(Employee.class);
        System.out.println("Serializing with version: " + osc.getSerialVersionUID());
        
        out.defaultWriteObject();
        out.writeInt(salary); // Custom serialization of transient field
    }
    
    private void readObject(ObjectInputStream in) 
            throws IOException, ClassNotFoundException {
        ObjectStreamClass osc = ObjectStreamClass.lookup(Employee.class);
        System.out.println("Deserializing with version: " + osc.getSerialVersionUID());
        
        in.defaultReadObject();
        this.salary = in.readInt(); // Custom deserialization
    }
    
    @Override
    public String toString() {
        return "Employee[name=" + name + ", salary=" + salary + "]";
    }
}

public class Main {
    public static void main(String[] args) {
        Employee emp = new Employee("Alice", 75000);
        
        // Serialize
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            
            oos.writeObject(emp);
            
            // Deserialize
            byte[] data = baos.toByteArray();
            try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
                 ObjectInputStream ois = new ObjectInputStream(bais)) {
                
                Employee deserialized = (Employee) ois.readObject();
                System.out.println("Deserialized: " + deserialized);
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

此示例展示了在自定义序列化期间正确使用 ObjectStreamClass。 序列化和反序列化上下文都已正确建立。 getSerialVersionUID 调用在没有抛出异常的情况下工作。

处理 NotActiveException

此示例演示了在处理潜在的 NotActiveException 场景时正确的异常处理。我们创建了一个实用程序方法,可以安全地检查 serialVersionUID。

Main.java
import java.io.*;

public class Main {
    
    public static long getSafeSerialVersionUID(Class clazz) {
        try {
            ObjectStreamClass osc = ObjectStreamClass.lookup(clazz);
            return osc.getSerialVersionUID();
        } catch (NotActiveException e) {
            System.err.println("Warning: Not in active serialization context");
            return ObjectStreamClass.lookup(clazz).getSerialVersionUID();
        }
    }

    public static void main(String[] args) {
        // Safe check outside serialization
        long suid = getSafeSerialVersionUID(String.class);
        System.out.println("String serialVersionUID: " + suid);
        
        // Safe check during serialization
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            
            suid = getSafeSerialVersionUID(Integer.class);
            System.out.println("Integer serialVersionUID: " + suid);
            
            oos.writeObject("Test");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此代码演示了针对 NotActiveException 的防御性编程。 实用程序方法优雅地处理了活动和非活动上下文。 catch 块中对 lookup 的第二次调用有效,因为它不需要活动上下文。

高级序列化示例

此示例显示了一个更复杂的场景,涉及嵌套序列化和正确的上下文管理。我们演示了正确的 ObjectStreamClass 使用。

Main.java
import java.io.*;

class Department implements Serializable {
    private static final long serialVersionUID = 3L;
    private String name;
    private Employee manager;
    
    public Department(String name, Employee manager) {
        this.name = name;
        this.manager = manager;
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        ObjectStreamClass osc = ObjectStreamClass.lookup(Department.class);
        System.out.println("Department serialVersionUID: " + osc.getSerialVersionUID());
        
        out.defaultWriteObject();
    }
    
    private void readObject(ObjectInputStream in) 
            throws IOException, ClassNotFoundException {
        ObjectStreamClass osc = ObjectStreamClass.lookup(Department.class);
        System.out.println("Department serialVersionUID: " + osc.getSerialVersionUID());
        
        in.defaultReadObject();
    }
}

public class Main {
    public static void main(String[] args) {
        Employee manager = new Employee("Bob", 90000);
        Department dept = new Department("Engineering", manager);
        
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            
            oos.writeObject(dept);
            
            byte[] data = baos.toByteArray();
            try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
                 ObjectInputStream ois = new ObjectInputStream(bais)) {
                
                Department deserialized = (Department) ois.readObject();
                System.out.println("Deserialized department: " + deserialized);
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

此高级示例展示了在嵌套对象序列化期间正确的 serialVersionUID 检查。 Department 和 Employee 类都维护了正确的序列化上下文。该示例演示了复杂但正确的使用模式。

来源

Java NotActiveException 类文档

在本文中,我们介绍了 Java NotActiveException 类的基本方面。了解此异常有助于防止序列化错误,并确保正确的 Java I/O 操作。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员。 从 2007 年开始撰写编程文章,至今已撰写了 1,400 多篇文章和八本电子书。 凭借八年以上的教学经验,我致力于分享我的知识,并帮助他人掌握编程概念。

列出所有Java教程