Java NotSerializableException 类
最后修改时间:2025 年 4 月 16 日
当需要一个实例实现 Serializable 接口但却没有时,会抛出 java.io.NotSerializableException
异常。它是 Java 对象序列化机制的一部分。序列化将对象转换为字节流。
当尝试对不可序列化对象进行序列化时,通常会发生此异常。Java 序列化机制会检查 Serializable
接口。如果没有实现该接口,则会抛出此异常,以防止无效的序列化。
NotSerializableException 类概述
NotSerializableException
继承自 ObjectStreamException
,表示序列化问题。异常消息会指明有问题的类。这是一个受检异常,需要在代码中显式处理。
public class NotSerializableException extends ObjectStreamException { public NotSerializableException(String classname); public NotSerializableException(); }
上面的代码展示了 NotSerializableException
类的结构。带参数的构造函数接受不可序列化类的名称。默认构造函数创建不包含特定类信息的异常。
基本序列化示例
此示例演示了在展示失败案例之前,如何进行正确的序列化。一个类必须实现 Serializable
接口才能被序列化。该示例展示了正确配置的类的成功序列化。
import java.io.*; class Person implements Serializable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{name='" + name + "', age=" + age + "}"; } } public class Main { public static void main(String[] args) { Person person = new Person("John Doe", 30); try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("person.ser"))) { oos.writeObject(person); System.out.println("Person serialized successfully"); } catch (IOException e) { e.printStackTrace(); } } }
此示例展示了 Person
类的成功序列化。该类实现了 Serializable
接口,允许对象序列化。ObjectOutputStream
将对象写入文件,没有错误。
不可序列化类示例
此示例演示了尝试序列化未实现 Serializable
接口的类时,发生的 NotSerializableException
异常。异常清楚地指出了哪个类导致了问题。
import java.io.*; class Product { // Doesn't implement Serializable private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } } public class Main { public static void main(String[] args) { Product product = new Product("Laptop", 999.99); try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("product.ser"))) { oos.writeObject(product); // This will throw NotSerializableException } catch (IOException e) { e.printStackTrace(); } } }
运行此代码会抛出 NotSerializableException
异常,因为 Product
没有实现 Serializable
接口。异常堆栈跟踪将在其消息中包含类名 (Product
)。这有助于在调试期间识别有问题的类。
不可序列化字段示例
即使一个类实现了 Serializable
接口,如果它包含不可序列化的字段,也可能会失败。此示例展示了这种情况,即一个可序列化的类包含一个不可序列化的字段。
import java.io.*; class Engine {} // Not serializable class Car implements Serializable { private String model; private Engine engine; // Non-serializable field public Car(String model, Engine engine) { this.model = model; this.engine = engine; } } public class Main { public static void main(String[] args) { Car car = new Car("Sedan", new Engine()); try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("car.ser"))) { oos.writeObject(car); // Fails due to Engine field } catch (IOException e) { e.printStackTrace(); } } }
此示例抛出 NotSerializableException
异常,因为 Car
包含一个不可序列化的 Engine
字段。所有字段都必须是可序列化的或标记为 transient
。异常消息将指定 Engine
为有问题的类。
瞬态字段解决方案
transient
关键字标记不应被序列化的字段。此示例通过将 engine 字段设为瞬态来修改前一个示例。序列化现在成功,跳过了 engine 字段。
import java.io.*; class Engine {} // Still not serializable class Car implements Serializable { private String model; private transient Engine engine; // Marked as transient public Car(String model, Engine engine) { this.model = model; this.engine = engine; } public Engine getEngine() { return engine; } } public class Main { public static void main(String[] args) { Car car = new Car("Sedan", new Engine()); try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("car.ser"))) { oos.writeObject(car); System.out.println("Car serialized successfully (engine skipped)"); } catch (IOException e) { e.printStackTrace(); } } }
此示例成功序列化了 Car
对象,因为 engine
字段被标记为 transient
。反序列化后,engine 字段将为 null
。当字段不需要持久化或可以重建时,此方法有效。
自定义序列化解决方案
为了获得更多控制权,类可以使用 writeObject
和 readObject
方法实现自定义序列化。此示例展示了如何使用自定义序列化来处理不可序列化的字段。
import java.io.*; class Engine { private String type; public Engine(String type) { this.type = type; } public String getType() { return type; } } class Car implements Serializable { private String model; private transient Engine engine; public Car(String model, Engine engine) { this.model = model; this.engine = engine; } private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); oos.writeObject(engine.getType()); // Serialize engine data } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); String engineType = (String) ois.readObject(); this.engine = new Engine(engineType); // Reconstruct engine } public Engine getEngine() { return engine; } } public class Main { public static void main(String[] args) { Car car = new Car("SUV", new Engine("V6")); try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("car.ser"))) { oos.writeObject(car); System.out.println("Car with custom serialization saved"); } catch (IOException e) { e.printStackTrace(); } } }
此示例演示了对具有不可序列化字段的类进行自定义序列化。writeObject
方法保存了 engine 的类型字符串。readObject
方法在反序列化期间重建了 engine。此方法提供了对序列化的完全控制。
继承和序列化
类层次结构中的序列化需要注意。如果超类不可序列化,则其字段将不会被序列化。此示例展示了扩展不可序列化类的行为。
import java.io.*; class Vehicle { // Not serializable protected String type; public Vehicle(String type) { this.type = type; } } class Truck extends Vehicle implements Serializable { private int capacity; public Truck(String type, int capacity) { super(type); this.capacity = capacity; } @Override public String toString() { return "Truck{type='" + type + "', capacity=" + capacity + "}"; } } public class Main { public static void main(String[] args) { Truck truck = new Truck("Heavy", 5000); try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("truck.ser"))) { oos.writeObject(truck); System.out.println("Truck serialized (but not Vehicle fields)"); } catch (IOException e) { e.printStackTrace(); } } }
此示例展示了使用继承的序列化。Truck
类是可序列化的,但其 Vehicle
超类不是。type
字段将不会被序列化,并且在反序列化后将为 null
。要包含超类字段,超类也必须实现 Serializable
接口。
来源
Java NotSerializableException 类文档
本教程涵盖了 Java 序列化中的 NotSerializableException
异常。我们探讨了处理序列化问题的根本原因、解决方案和最佳实践。理解这些概念对于在 Java 中有效实现对象持久化至关重要。
作者
列出所有Java教程。