Java ObjectInput 接口
最后修改时间:2025 年 4 月 16 日
java.io.ObjectInput 接口继承了 DataInput,并提供了读取对象和基本数据类型的功能。它主要用于 Java 序列化机制中的对象反序列化。
ObjectInput 由诸如 ObjectInputStream 之类的类实现,这些类执行对象的反序列化。 该接口提供了从输入源读取对象、基本类型和数组的方法。它还支持读取字节和跳过数据。
ObjectInput 接口概述
ObjectInput 接口结合了对象读取和基本数据读取功能。 关键方法包括对象反序列化、基本类型读取和流控制操作。 所有方法都可以抛出 IOException 以表示 I/O 错误。
public interface ObjectInput extends DataInput, AutoCloseable {
Object readObject() throws ClassNotFoundException, IOException;
int read() throws IOException;
int read(byte[] b) throws IOException;
int read(byte[] b, int off, int len) throws IOException;
long skip(long n) throws IOException;
int available() throws IOException;
void close() throws IOException;
}
上面的代码显示了 ObjectInput 的核心方法。 该接口继承了 DataInput,它提供了基本读取方法。 readObject 方法是反序列化对象的主要方法。
基本对象反序列化
ObjectInput 最基本的用途是反序列化对象。 这要求对象的类实现 Serializable。 readObject 方法读取并重建序列化的对象。
import java.io.FileInputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.IOException;
class Person implements java.io.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) {
try (ObjectInput in = new ObjectInputStream(
new FileInputStream("person.ser"))) {
Person p = (Person) in.readObject();
System.out.println("Deserialized Person: " + p);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
此示例演示了基本对象反序列化。 Person 类必须实现 Serializable。 readObject 方法从序列化数据重建对象。 强制转换是必要的,因为 readObject 返回 Object。
读取基本类型
ObjectInput 从 DataInput 继承基本类型读取方法。 这些包括读取所有 Java 基本类型的方法。 这些方法以网络字节顺序(大端)读取数据。
import java.io.FileInputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try (ObjectInput in = new ObjectInputStream(
new FileInputStream("primitives.dat"))) {
boolean bool = in.readBoolean();
byte b = in.readByte();
char c = in.readChar();
short s = in.readShort();
int i = in.readInt();
long l = in.readLong();
float f = in.readFloat();
double d = in.readDouble();
System.out.println("Boolean: " + bool);
System.out.println("Byte: " + b);
System.out.println("Char: " + c);
System.out.println("Short: " + s);
System.out.println("Int: " + i);
System.out.println("Long: " + l);
System.out.println("Float: " + f);
System.out.println("Double: " + d);
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例显示了从 ObjectInput 流读取基本类型。 数据必须以写入时的相同顺序读取。 每种方法都读取该类型所需的字节数。 流必须包含足够的数据用于所有读取。
读取字节数组
ObjectInput 提供了读取字节数组的方法。 read(byte[]) 方法尝试填充整个数组。 read(byte[], int, int) 方法将数据读入数组的一部分。
import java.io.FileInputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
try (ObjectInput in = new ObjectInputStream(
new FileInputStream("bytes.dat"))) {
// Read full array
byte[] buffer1 = new byte[10];
int bytesRead1 = in.read(buffer1);
System.out.println("Read " + bytesRead1 + " bytes: " +
Arrays.toString(buffer1));
// Read partial array
byte[] buffer2 = new byte[20];
int bytesRead2 = in.read(buffer2, 5, 10);
System.out.println("Read " + bytesRead2 + " bytes into offset 5: " +
Arrays.toString(buffer2));
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例演示了读取字节数组。 第一次读取尝试填充整个 10 字节数组。 第二次读取将 10 个字节放入 20 字节数组中,从偏移量 5 开始。这两种方法都返回实际读取的字节数。
跳过字节和检查可用性
skip 方法允许跳过输入流中的字节。 available 方法估计可以在不阻塞的情况下读取的字节数。 这些对于流导航和状态检查很有用。
import java.io.ByteArrayInputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
byte[] data = new byte[100];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) i;
}
try (ObjectInput in = new ObjectInputStream(
new ByteArrayInputStream(data))) {
System.out.println("Initially available: " + in.available());
// Skip first 20 bytes
long skipped = in.skip(20);
System.out.println("Skipped " + skipped + " bytes");
// Read next byte
int nextByte = in.read();
System.out.println("Next byte: " + nextByte);
System.out.println("Now available: " + in.available());
// Skip remaining
skipped = in.skip(100);
System.out.println("Skipped " + skipped + " more bytes");
System.out.println("Final available: " + in.available());
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例显示了跳过字节和检查可用性。 skip 方法可能跳过的字节少于请求的字节。 available 方法返回剩余的字节。 跳过所有字节后,available 返回 0。
读取多个对象
ObjectInput 可以从流中按顺序读取多个对象。 每个 readObject 调用都读取下一个对象。 对象必须以写入时的相同顺序读取。
import java.io.FileInputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.IOException;
class Product implements java.io.Serializable {
private String name;
private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return String.format("Product{name='%s', price=%.2f}", name, price);
}
}
public class Main {
public static void main(String[] args) {
try (ObjectInput in = new ObjectInputStream(
new FileInputStream("products.ser"))) {
// Read first object
Product p1 = (Product) in.readObject();
System.out.println("First product: " + p1);
// Read second object
Product p2 = (Product) in.readObject();
System.out.println("Second product: " + p2);
// Read primitive between objects
int count = in.readInt();
System.out.println("Product count: " + count);
// Read third object
Product p3 = (Product) in.readObject();
System.out.println("Third product: " + p3);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
此示例读取与基本数据穿插的多个对象。 对象和基本类型必须以写入时的完全相同的顺序读取。 尝试以错误的顺序读取对象将导致异常。 该流维护序列化图结构。
来源
在本文中,我们介绍了 Java ObjectInput 接口的基本方法和功能。 理解这些概念对于在 Java 应用程序中使用对象序列化和反序列化至关重要。
作者
列出所有Java教程。