java.lang.Object java.io.InputStream java.io.ObjectInputStream
public class ObjectInputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
ObjectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中显示的类相匹配。使用标准机制按需加载类。
只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。
readObject
方法用于从流读取对象。应该使用 Java 的安全强制转换来获取所需的类型。在 Java 中,字符串和数组都是对象,所以在序列化期间将其视为对象。读取时,需要将其强制转换为期望的类型。
可以使用 DataInput 上的适当方法从流读取基本数据类型。
默认情况下,对象的反序列化机制会将每个字段的内容恢复为写入时它所具有的值和类型。反序列化进程将忽略声明为瞬态或静态的字段。对其他对象的引用使得根据需要从流中读取这些对象。使用引用共享机制能够正确地恢复对象的图形。反序列化时始终分配新对象,这样可以避免现有对象被重写。
读取对象类似于运行新对象的构造方法。为对象分配内存并将其初始化为零 (NULL)。为不可序列化类调用无参数构造方法,然后从以最接近 java.lang.object 的可序列化类开始和以对象的最特定类结束的流恢复可序列化类的字段。
例如,要从由 ObjectOutputStream 中的示例写入的流读取:
FileInputStream fis = new FileInputStream("t.tmp"); ObjectInputStream ois = new ObjectInputStream(fis); int i = ois.readInt(); String today = (String) ois.readObject(); Date date = (Date) ois.readObject(); ois.close();
类控制实现 java.io.Serializable 或 java.io.Externalizable 接口时的序列化方式。
实现 Serializable 接口允许对象序列化,以保存和恢复对象的全部状态,并且允许类在写入流时的状态和从流读取时的状态之间变化。它自动遍历对象之间的引用,保存和恢复全部图形。
在序列化和反序列化进程中需要特殊处理的 Serializable 类应该实现以下方法:
private void writeObject(java.io.ObjectOutputStream stream) throws IOException; private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException;
readObject 方法负责使用通过对应的 writeObject 方法写入流的数据,为特定类读取和恢复对象的状态。该方法本身的状态,不管是属于其超类还是属于其子类,都没有关系。恢复状态的方法是,从个别字段的 ObjectInputStream 读取数据并将其分配给对象的适当字段。DataInput 支持读取基本数据类型。
尝试读取由对应的 writeObject 方法写入的超出自定义数据边界的对象数据将导致抛出 OptionalDataException(eof 字段值为 true)。超出已分配数据末尾的非对象读取以指示流末尾的方式反映数据结束:按位读取与字节读取或字节数读取一样,将返回 -1,基元读取将抛出 EOFException。如果不存在对应的 writeObject 方法,则默认的序列化数据的末尾标记已分配数据的末尾。
从 readExternal 方法发出的基元和对象读取调用的行为方式一样:如果流已经定位在由相应 writeExternal 方法写入的数据末尾,则对象读取将抛出 OptionalDataException(其 eof 设置为 true),按位读取将返回 -1,基元读取将抛出 EOFException。注意,此行为不适用于使用旧 ObjectStreamConstants.PROTOCOL_VERSION_1
协议写入的流,在这些流中,没有划分出由 writeExternal 方法写入的数据末尾,因此无法检测。
如果序列化流没有将给定类列为要反序列化的对象的超类,则 readObjectNoData 方法负责初始化其特定类的对象状态。在接收方使用的反序列化实例类的版本不同于发送方,并且接收者版本扩展的类不是发送者版本扩展的类时,此事可能发生。如果序列化流已经被篡改,也会发生这种情况;因此,不管源流是“敌意的”还是不完整的,readObjectNoData 方法都可以用来正确地初始化反序列化的对象。
对于没有实现 java.io.Serializable 接口的任何对象,序列化不会对其字段进行读取或赋值。非 serializable 的 Object 的子类可以为 serializable。在此情况下,非 serializable 类必须具有无参数的构造方法以允许其字段能被初始化。在此情况下,子类负责保存和恢复非 serializable 类的状态。经常出现的情况是,该类的字段是可访问的(public、package 或 protected),或者存在可用于恢复状态的 get 和 set 方法。
反序列化对象进程中发生的所有异常将由 ObjectInputStream 捕获并将中止读取进程。
实现 Externalizable 接口允许对象假定可以完全控制对象的序列化形式的内容和格式。调用 Externalizable 接口的方法(writeExternal 和 readExternal)来保存和恢复对象状态。当这两种方法被某个类实现时,它们可以使用 ObjectOutput 和 ObjectInput 的所有方法读写其本身的状态。对象负责处理出现的任何版本控制。
Enum 常量的反序列化不同于普通的 serializable 或 externalizable 对象。Enum 常量的序列化形式只包含其名称;不传送常量的字段值。要反序列化 enum 常量,ObjectInputStream 需要从流中读取常量的名称;然后将 enum 常量的基本类型和接收到的常量名称作为参数,调用静态方法 Enum.valueOf(Class, String)
获取反序列化的常量。与其他 serializable 或 externalizable 对象一样,enum 常量可以作为序列化流中随后出现的反向引用的目标。不可以自定义 enum 常量的反序列化进程:在反序列化期间,enum 类型所定义的任何与类有关的 readObject、readObjectNoData 和 readResolve 方法都将被忽略。类似地,任何 serialPersistentFields 或 serialVersionUID 字段声明也将被忽略(所有 enum 类型都有一个固定的 0L 的 serialVersionUID)。
DataInput
,
ObjectOutputStream
,
Serializable
,
对象序列化规范:Object Input Classes 第三节
嵌套类摘要 | |
---|---|
static class |
ObjectInputStream.GetField 提供对从输入流读取的持久字段的访问权限。 |
字段摘要 |
---|
构造方法摘要 | |
---|---|
protected |
ObjectInputStream() 为完全重新实现 ObjectInputStream 的子类提供一种方式,让它不必分配仅由 ObjectInputStream 的实现使用的私有数据。 |
|
ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream。 |
方法摘要 | |
---|---|
int |
available() 返回可以不受阻塞地读取的字节数。 |
void |
close() 关闭输入流。 |
void |
defaultReadObject() 从此流读取当前类的非静态和非瞬态字段。 |
protected boolean |
enableResolveObject(boolean enable) 使流允许从该流读取的对象被替代。 |
int |
read() 读取数据字节。 |
int |
read(byte[] buf, int off, int len) 读入 byte 数组。 |
boolean |
readBoolean() 读取一个 boolean 值。 |
byte |
readByte() 读取一个 8 位的字节。 |
char |
readChar() 读取一个 16 位的 char 值。 |
protected ObjectStreamClass |
readClassDescriptor() 从序列化流读取类描述符。 |
double |
readDouble() 读取一个 64 位的 double 值。 |
ObjectInputStream.GetField |
readFields() 按名称从流中读取持久字段并使其可用。 |
float |
readFloat() 读取一个 32 位的 float 值。 |
void |
readFully(byte[] buf) 读取字节,同时阻塞直至读取所有字节。 |
void |
readFully(byte[] buf, int off, int len) 读取字节,同时阻塞直至读取所有字节。 |
int |
readInt() 读取一个 32 位的 int 值。 |
String |
readLine() 已过时。 此方法不能正确地将字节转换为字符。请参见 DataInputStream 以获取详细信息和替代方法。 |
long |
readLong() 读取一个 64 位的 long 值。 |
Object |
readObject() 从 ObjectInputStream 读取对象。 |
protected Object |
readObjectOverride() 此方法由 ObjectOutputStream 的受信任子类调用,这些子类使用受保护的无参数构造方法构造 ObjectOutputStream。 |
short |
readShort() 读取一个 16 位的 short 值。 |
protected void |
readStreamHeader() 提供的 readStreamHeader 方法允许子类读取并验证它们自己的流头部。 |
Object |
readUnshared() 从 ObjectInputStream 读取“非共享”对象。 |
int |
readUnsignedByte() 读取一个无符号的 8 位字节。 |
int |
readUnsignedShort() 读取一个无符号的 16 位 short 值。 |
String |
readUTF() 读取 UTF-8 修改版格式的 String。 |
void |
registerValidation(ObjectInputValidation obj, int prio) 在返回图形前注册要验证的对象。 |
protected Class<?> |
resolveClass(ObjectStreamClass desc) 加载指定流类描述的本地等价类。 |
protected Object |
resolveObject(Object obj) 在反序列化期间,此方法允许 ObjectInputStream 的受信任子类使用一个对象替代另一个。 |
protected Class<?> |
resolveProxyClass(String[] interfaces) 返回一个代理类,该类实现在代理类描述符中命名的接口;子类可以实现此方法,以便从流及动态代理类的描述符中读取自定义数据,允许它们使用接口和代理类的替换加载机制。 |
int |
skipBytes(int len) 跳过字节。 |
从类 java.io.InputStream 继承的方法 |
---|
mark, markSupported, read, reset, skip |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
从接口 java.io.ObjectInput 继承的方法 |
---|
read, skip |
构造方法详细信息 |
---|
public ObjectInputStream(InputStream in) throws IOException
如果安装了安全管理器,则重写 ObjectInputStream.readFields 或 ObjectInputStream.readUnshared 方法的子类的构造方法直接或间接调用此构造方法时,它将对 "enableSubclassImplementation" SerializablePermission 进行检查。
in
- 要从中读取的输入流
StreamCorruptedException
- 如果流的头部不正确
IOException
- 如果读取流头部时发生 I/O 错误
SecurityException
- 如果不受信任的子类非法重写安全敏感的方法
NullPointerException
- 如果
in
为
null
ObjectInputStream()
,
readFields()
,
ObjectOutputStream.ObjectOutputStream(OutputStream)
protected ObjectInputStream() throws IOException, SecurityException
如果已经安装了安全管理器,则此方法首先通过 SerializablePermission("enableSubclassImplementation")
权限调用安全管理器的 checkPermission
方法,以确保可以启用子类化。
SecurityException
- 如果安全管理器存在并且其
checkPermission
方法不允许启用子类化。
IOException
SecurityManager.checkPermission(java.security.Permission)
,
SerializablePermission
方法详细信息 |
---|
public final Object readObject() throws IOException, ClassNotFoundException
通过完全恢复根对象的所有字段及其引用的对象来完全恢复根对象。此时,对象验证回调的执行顺序基于其注册优先级。回调由对象在其个别恢复时(通过 readObject 特定方法)进行注册。
当 InputStream 中出现问题或者遇到不应反序列化的类时,将抛出异常。所有异常对于 InputStream 而言都是致命的,将使其处于不确定状态;是忽略还是恢复流状态取决于调用者。
ObjectInput
中的
readObject
ClassNotFoundException
- 找不到序列化对象的类。
InvalidClassException
- 序列化使用的类出了问题。
StreamCorruptedException
- 流中的控制信息不一致。
OptionalDataException
- 在流中找到基本类型数据而非对象。
IOException
- 任何常规的输入/输出相关的异常。
protected Object readObjectOverride() throws IOException, ClassNotFoundException
ClassNotFoundException
- 找不到序列化对象的类定义。
OptionalDataException
- 在流中找到基本类型数据而非对象。
IOException
- 如果从底层流执行读操作时发生 I/O 错误
ObjectInputStream()
,
readObject()
public Object readUnshared() throws IOException, ClassNotFoundException
重写此方法的 ObjectInputStream 子类只能在处理 "enableSubclassImplementation" SerializablePermission 的安全上下文中构造;在不具有此权限的情况下,任何实例化这种子类的尝试都将导致抛出 SecurityException。
ClassNotFoundException
- 如果找不到要反序列化的对象的类
StreamCorruptedException
- 如果流中的控制信息不一致
ObjectStreamException
- 如果流中已经出现了要反序列化的对象
OptionalDataException
- 如果基本数据是流中的下一项
IOException
- 如果在反序列化期间发生 I/O 错误
public void defaultReadObject() throws IOException, ClassNotFoundException
ClassNotFoundException
- 如果找不到序列化对象的类。
IOException
- 如果发生 I/O 错误。
NotActiveException
- 如果目前流没有正在读取对象。
public ObjectInputStream.GetField readFields() throws IOException, ClassNotFoundException
GetField
对象
ClassNotFoundException
- 如果找不到序列化对象的类。
IOException
- 如果发生 I/O 错误。
NotActiveException
- 如果目前流没有正在读取对象。
public void registerValidation(ObjectInputValidation obj, int prio) throws NotActiveException, InvalidObjectException
obj
- 接收验证回调的对象。
prio
- 控制回调的顺序;零是个好的默认值。使用较大数进行较早的回调,使用较小数进行较晚的回调。在一个优先级中,回调的处理没有特定顺序。
NotActiveException
- 因为目前流没有正在读取对象,所以注册回调无效。
InvalidObjectException
- 验证对象为 null。
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException
ObjectOutputStream
中的相应方法是 annotateClass
。对于流中的每个唯一类,此方法只调用一次。此方法可以由子类实现,从而使用替换加载机制,但是必须返回 Class
对象。返回后,如果该类不是数组类,则它的 serialVersionUID 将与序列化类的 serialVersionUID 进行比较,如果不匹配,则反序列化失败,并抛出 InvalidClassException
。
在 ObjectInputStream
中此方法的默认实现返回调用
Class.forName(desc.getName(), false, loader)的结果,其中
loader
按以下情形确定:如果当前线程的堆栈上存在一种方法,它的声明类由用户定义的类加载器定义(不是一个为实现反射调用而生成的类),则
loader
是对应于最接近当前执行帧的这些方法的类加载器;否则,
loader
为
null
。如果此调用导致抛出
ClassNotFoundException
,且传递的
ObjectStreamClass
实例的名称是 Java 语言中基本数据类型或 void 关键字,那么将返回表示该基本类型或 void 的
Class
对象(例如,名称为
"int"
的
ObjectStreamClass
将被解析为
Integer.TYPE
)。否则,将向此方法的调用者抛出
ClassNotFoundException
。
desc
-
ObjectStreamClass
类的实例
desc
的
Class
对象
IOException
- 任何常规输入/输出异常
ClassNotFoundException
- 如果找不到序列化对象的类。
protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException
对于流中的每个唯一的代理类描述符,此方法只调用一次。
ObjectOutputStream
中的相应方法是 annotateProxyClass
。对于重写此方法的 ObjectInputStream
的给定子类,ObjectOutputStream
的相应子类中的 annotateProxyClass
方法必须写入由此方法读取的任何数据或对象。
ObjectInputStream
中此方法的默认实现返回调用 Proxy.getProxyClass
的结果,同时带有在 interfaces
参数中指定接口的 Class
对象的列表。每个接口名称 i
的 Class
对象都是调用以下语句返回的值
Class.forName(i, false, loader)其中,
loader
是执行堆栈上的第一个非
null
类加载器,如果在堆栈上不存在非
null
加载器(类加载器选项与
resolveClass
方法使用的相同),则为
null
。如果所有解析的接口都是公共的,则
loader
的这一相同值还是传递给
Proxy.getProxyClass
的类加载器;如果出现非公共接口,则传递他们的类加载器(如果遇到一个以上的非公共接口类加载器,则抛出
IllegalAccessError
)。如果
Proxy.getProxyClass
抛出
IllegalArgumentException
,则
resolveProxyClass
将抛出包含
IllegalArgumentException
的
ClassNotFoundException
。
interfaces
- 代理类描述符中反序列化的接口名称的列表
IOException
- 底层
InputStream
抛出任何异常
ClassNotFoundException
- 如果找不到代理类或任何指定接口
ObjectOutputStream.annotateProxyClass(Class)
protected Object resolveObject(Object obj) throws IOException
此方法在读取对象之后而在从 readObject 返回之前调用。默认的 resolveObject 方法仅返回相同的对象。
子类在取代对象时,必须确保替代对象与存储引用的每个字段兼容。如果对象的类型不是字段或数组元素类型的子类,则通过引发异常中止序列化并且不存储对象。
此方法仅在首次遇到每个对象时调用一次。对象的所有后续引用都将被重定向到新对象。
obj
- 要替代的对象
IOException
- 任何常规的输入/输出异常。
protected boolean enableResolveObject(boolean enable) throws SecurityException
如果 enable 为真,并且安装了安全管理器,则此方法首先使用 SerializablePermission("enableSubstitution")
权限调用安全管理器的 checkPermission
方法,以确保使流允许从该流读取的对象被替代。
enable
- 如果为 true,则允许为每个要反序列化的对象使用
resolveObject
SecurityException
- 如果安全管理器存在,且其
checkPermission
方法拒绝流允许从要替代的流读取对象。
SecurityManager.checkPermission(java.security.Permission)
,
SerializablePermission
protected void readStreamHeader() throws IOException, StreamCorruptedException
IOException
- 如果从底层
InputStream
读取时发生 I/O 错误
StreamCorruptedException
- 如果流中的控制信息不一致
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException
writeClassDescriptor
方法编写的)。默认情况下,此方法根据对象序列化规范中定义的格式读取类描述符。
IOException
- 如果发生 I/O 错误。
ClassNotFoundException
- 如果找不到类描述符表示形式中使用的序列化对象的 Class
ObjectOutputStream.writeClassDescriptor(java.io.ObjectStreamClass)
public int read() throws IOException
ObjectInput
中的
read
InputStream
中的
read
IOException
- 如果发生 I/O 错误。
public int read(byte[] buf, int off, int len) throws IOException
ObjectInput
中的
read
InputStream
中的
read
buf
- 读入数据的缓冲区
off
- 数据的初始偏移量
len
- 读取的最大字节数
IOException
- 如果发生 I/O 错误。
DataInputStream.readFully(byte[],int,int)