Java InvalidObjectException 类
最后修改时间:2025 年 4 月 16 日
当验证失败时,在对象反序列化期间会抛出 java.io.InvalidObjectException。它表明反序列化的对象未能通过验证检查。此异常通常由 readObject 方法抛出。
InvalidObjectException 扩展了 ObjectStreamException,并且是 Java 序列化机制的一部分。当对象在反序列化后状态无效时使用。该异常通常包含一个详细的消息,解释验证失败的原因。
InvalidObjectException 类概述
InvalidObjectException 是 Java I/O 包中的一个已检查异常。当对象在反序列化期间未能通过其内部一致性检查时抛出。该类提供了构造函数,用于创建带有详细消息的异常。
public class InvalidObjectException extends ObjectStreamException {
public InvalidObjectException(String reason);
}
上面的代码展示了 InvalidObjectException 的简单结构。它有一个接受原因字符串的构造函数。此字符串应该解释对象验证在反序列化期间失败的原因。
InvalidObjectException 基本示例
此示例演示了一个简单的情况,即在反序列化期间抛出 InvalidObjectException。我们创建一个类,该类在其 readObject 方法中实现自定义验证。
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;
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if (age < 0 || age > 120) {
throw new InvalidObjectException("Invalid age value: " + age);
}
}
}
public class Main {
public static void main(String[] args) {
try {
Person p = new Person("John", 150);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(p);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Person deserialized = (Person) ois.readObject();
} catch (InvalidObjectException e) {
System.err.println("Validation failed: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
在此示例中,Person 类验证年龄在反序列化期间是否在 0 到 120 之间。当提供无效年龄 (150) 时,readObject 方法抛出 InvalidObjectException。异常消息清楚地说明了验证失败的原因。
使用 InvalidObjectException 进行自定义验证
此示例展示了更复杂的验证逻辑,它检查多个字段及其关系。该异常提供了关于具体哪些内容验证失败的详细信息。
import java.io.*;
class BankAccount implements Serializable {
private String accountNumber;
private double balance;
private double overdraftLimit;
public BankAccount(String accountNumber, double balance, double overdraftLimit) {
this.accountNumber = accountNumber;
this.balance = balance;
this.overdraftLimit = overdraftLimit;
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if (accountNumber == null || accountNumber.length() != 10) {
throw new InvalidObjectException(
"Account number must be exactly 10 characters");
}
if (overdraftLimit < 0) {
throw new InvalidObjectException(
"Overdraft limit cannot be negative");
}
if (balance < -overdraftLimit) {
throw new InvalidObjectException(
"Balance cannot be below overdraft limit");
}
}
}
public class Main {
public static void main(String[] args) {
try {
BankAccount account = new BankAccount("123456789", -1000, 500);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(account);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
BankAccount deserialized = (BankAccount) ois.readObject();
} catch (InvalidObjectException e) {
System.err.println("Account validation failed: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
BankAccount 类在反序列化期间执行三个验证检查。它验证账号格式,确保透支限额为非负数,并检查余额是否符合透支限额。当任何检查失败时,将抛出一个描述性的 InvalidObjectException。
将 InvalidObjectException 与 Externalizable 一起使用
此示例演示了将 InvalidObjectException 与 Externalizable 接口一起使用。验证发生在读取所有字段后的 readExternal 方法中。
import java.io.*;
class Product implements Externalizable {
private String id;
private String name;
private double price;
private int stock;
public Product() {} // Required for Externalizable
public Product(String id, String name, double price, int stock) {
this.id = id;
this.name = name;
this.price = price;
this.stock = stock;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(id);
out.writeUTF(name);
out.writeDouble(price);
out.writeInt(stock);
}
@Override
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
id = in.readUTF();
name = in.readUTF();
price = in.readDouble();
stock = in.readInt();
if (price <= 0) {
throw new InvalidObjectException("Price must be positive");
}
if (stock < 0) {
throw new InvalidObjectException("Stock cannot be negative");
}
if (id == null || id.isEmpty()) {
throw new InvalidObjectException("Product ID is required");
}
}
}
public class Main {
public static void main(String[] args) {
try {
Product product = new Product("", "Laptop", -999.99, -5);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(product);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Product deserialized = (Product) ois.readObject();
} catch (InvalidObjectException e) {
System.err.println("Product validation failed: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Product 类实现了 Externalizable 并在 readExternal 中执行验证。它检查价格是否为正数,库存是否为非负数,以及产品 ID 是否为空。每个验证失败都会抛出带有特定错误消息的 InvalidObjectException。
使用 InvalidObjectException 进行嵌套对象验证
此示例展示了如何在反序列化期间验证嵌套对象。父对象的验证包括检查其子对象的有效性。
import java.io.*;
class Address implements Serializable {
private String street;
private String city;
private String zipCode;
public Address(String street, String city, String zipCode) {
this.street = street;
this.city = city;
this.zipCode = zipCode;
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if (street == null || city == null || zipCode == null) {
throw new InvalidObjectException("Address fields cannot be null");
}
}
}
class Customer implements Serializable {
private String name;
private Address address;
public Customer(String name, Address address) {
this.name = name;
this.address = address;
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if (name == null || name.isEmpty()) {
throw new InvalidObjectException("Customer name is required");
}
if (address == null) {
throw new InvalidObjectException("Address is required");
}
}
}
public class Main {
public static void main(String[] args) {
try {
Customer customer = new Customer("", new Address(null, null, null));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(customer);
oos.close();
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Customer deserialized = (Customer) ois.readObject();
} catch (InvalidObjectException e) {
System.err.println("Customer validation failed: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
在此示例中,Customer 和 Address 类都在反序列化期间执行验证。Customer 验证其姓名和地址字段,而 Address 验证其自己的字段。验证失败会级联,并带有详细的错误消息。
优雅地处理 InvalidObjectException
此示例演示了处理 InvalidObjectException 时的正确错误处理方法。它展示了如何从反序列化失败中恢复并提供用户友好的错误消息。
import java.io.*;
class Configuration implements Serializable {
private String environment;
private int timeout;
private boolean debugMode;
public Configuration(String environment, int timeout, boolean debugMode) {
this.environment = environment;
this.timeout = timeout;
this.debugMode = debugMode;
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if (!"prod".equals(environment) && !"dev".equals(environment) {
throw new InvalidObjectException(
"Invalid environment: " + environment);
}
if (timeout < 1 || timeout > 300) {
throw new InvalidObjectException(
"Timeout must be between 1 and 300 seconds");
}
}
}
public class Main {
public static void main(String[] args) {
String filename = "config.ser";
try {
// Try to deserialize configuration
Configuration config = loadConfiguration(filename);
System.out.println("Configuration loaded successfully");
} catch (InvalidObjectException e) {
System.err.println("Invalid configuration: " + e.getMessage());
System.out.println("Loading default configuration instead");
Configuration defaultConfig = new Configuration("dev", 30, false);
// Use default configuration...
} catch (Exception e) {
System.err.println("Error loading configuration: " + e.getMessage());
}
}
private static Configuration loadConfiguration(String filename)
throws IOException, ClassNotFoundException {
try (ObjectInputStream ois =
new ObjectInputStream(new FileInputStream(filename))) {
return (Configuration) ois.readObject();
}
}
}
此示例展示了一种处理 InvalidObjectException 的实用方法。当配置反序列化由于无效值而失败时,应用程序将回退到默认设置。来自异常的错误消息用于告知用户发生了什么错误。
来源
Java InvalidObjectException 类文档
在本文中,我们涵盖了 Java InvalidObjectException 类的基本方面。理解这个异常对于在 Java 应用程序中实现反序列化期间的健壮的对象验证至关重要。
作者
列出所有Java教程。