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教程。