鸿蒙OS开发文档 鸿蒙OS ObjectOutputStream

2024-02-25 开发教程 鸿蒙OS开发文档 匿名 3

ObjectOutputStream

java.lang.Object
|---java.io.OutputStream
|---|---java.io.ObjectOutputStream

public class ObjectOutputStream
extends OutputStream
implements ObjectOutput, ObjectStreamConstants

ObjectOutputStream 将 Java 对象的原始数据类型和图形写入 OutputStream。 可以使用 ObjectInputStream 读取(重构)对象。 对象的持久存储可以通过使用流的文件来实现。 如果流是网络套接字流,则可以在另一个主机或另一个进程中重构对象。

只有支持 java.io.Serializable 接口的对象才能写入流。 每个可序列化对象的类都经过编码,包括类的类名和签名、对象的字段和数组的值,以及从初始对象引用的任何其他对象的闭包。

writeObject 方法用于将对象写入流。任何对象,包括字符串和数组,都是用 writeObject 编写的。可以将多个对象或原语写入流。对象必须从相应的 ObjectInputstream 以与写入时相同的类型和相同的顺序读回。

原始数据类型也可以使用 DataOutput 中的适当方法写入流。也可以使用 writeUTF 方法写入字符串。

对象的默认序列化机制写入对象的类、类签名以及所有非瞬态和非静态字段的值。对其他对象的引用(瞬态或静态字段除外)也会导致这些对象被写入。使用引用共享机制对单个对象的多个引用进行编码,以便对象的图形可以恢复到与原始对象写入时相同的形状。

比如写一个ObjectInputStream中的例子可以读取的对象:

FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeInt(12345);
oos.writeObject("Today");
oos.writeObject(new Date());
oos.close();

在序列化和反序列化过程中需要特殊处理的类必须实现具有这些确切签名的特殊方法:

private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException
private void readObjectNoData()
throws ObjectStreamException;

writeObject 方法负责为其特定类写入对象的状态,以便相应的 readObject 方法可以恢复它。该方法不需要关注属于对象的超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的原始数据类型的方法将各个字段写入 ObjectOutputStream 来保存状态。

序列化不会写出任何未实现 java.io.Serializable 接口的对象的字段。不可序列化的对象的子类可以是可序列化的。在这种情况下,不可序列化的类必须有一个无参数的构造函数来允许其字段被初始化。在这种情况下,子类负责保存和恢复不可序列化类的状态。通常情况下,该类的字段是可访问的(公共的、包的或受保护的),或者存在可用于恢复状态的 get 和 set 方法。

可以通过实现抛出 NotSerializableException 的 writeObject 和 readObject 方法来防止对象的序列化。异常将被 ObjectOutputStream 捕获并中止序列化过程。

实现 Externalizable 接口允许对象完全控制对象序列化形式的内容和格式。调用 Externalizable 接口的方法 writeExternal 和 readExternal 来保存和恢复对象状态。当由一个类实现时,它们可以使用 ObjectOutput 和 ObjectInput 的所有方法写入和读取自己的状态。对象负责处理发生的任何版本控制。

枚举常量的序列化方式与普通的可序列化或可外部化对象不同。枚举常量的序列化形式仅由其名称组成;不传输常量的字段值。为了序列化枚举常量,ObjectOutputStream 写入常量的 name 方法返回的字符串。与其他可序列化或可外部化的对象一样,枚举常量可以充当随后出现在序列化流中的反向引用的目标。无法自定义枚举常量序列化的过程;在序列化过程中,枚举类型定义的任何类特定的 writeObject 和 writeReplace 方法都会被忽略。同样,任何 serialPersistentFields 或 serialVersionUID 字段声明也将被忽略——所有枚举类型都有一个固定的 serialVersionUID 为 0L。

原始数据(不包括可序列化字段和可外部化数据)以块数据记录的形式写入 ObjectOutputStream。块数据记录由标题和数据组成。块数据头由一个标记和跟随头的字节数组成。连续的原始数据写入合并到一个块数据记录中。用于块数据记录的阻塞因子为 1024 字节。每个块数据记录将被填充到 1024 字节,或者在块数据模式终止时写入。对 ObjectOutputStream 方法 writeObject、defaultWriteObject 和 writeFields 的调用最初会终止任何现有的块数据记录。

Since:

JDK1.1

嵌套类摘要

修饰符和类型描述
static classObjectOutputStream.PutField提供对要写入 ObjectOutput 的持久字段的编程访问。

字段摘要

从接口 java.io.ObjectStreamConstants 继承的字段
baseWireHandle, PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, SC_BLOCK_DATA, SC_ENUM, SC_EXTERNALIZABLE, SC_SERIALIZABLE, SC_WRITE_METHOD, STREAM_MAGIC, STREAM_VERSION, SUBCLASS_IMPLEMENTATION_PERMISSION, SUBSTITUTION_PERMISSION, TC_ARRAY, TC_BASE, TC_BLOCKDATA, TC_BLOCKDATALONG, TC_CLASS, TC_CLASSDESC, TC_ENDBLOCKDATA, TC_ENUM, TC_EXCEPTION, TC_LONGSTRING, TC_MAX, TC_NULL, TC_OBJECT, TC_PROXYCLASSDESC, TC_REFERENCE, TC_RESET, TC_STRING

构造函数摘要

修饰符构造函数描述
protectedObjectOutputStream()为完全重新实现 ObjectOutputStream 的子类提供一种方法,使其不必分配刚刚由 ObjectOutputStream 的实现使用的私有数据。
ObjectOutputStream(OutputStream out)创建一个写入指定 OutputStream 的 ObjectOutputStream。

方法总结

修饰符和类型方法描述
protected voidannotateClass(Class<?> cl)子类可以实现此方法以允许将类数据存储在流中。
protected voidannotateProxyClass(Class<?> cl)子类可以实现此方法以将自定义数据与动态代理类的描述符一起存储在流中。
voidclose()关闭流。
voiddefaultWriteObject()将当前类的非静态和非瞬态字段写入此流。
protected voiddrain()排出 ObjectOutputStream 中的所有缓冲数据。
protected booleanenableReplaceObject(boolean enable)使流能够替换流中的对象。
voidflush()冲洗流。
ObjectOutputStream.PutFieldputFields()检索用于缓冲要写入流的持久字段的对象。
protected ObjectreplaceObject(Object obj)此方法将允许 ObjectOutputStream 的受信任子类在序列化期间用一个对象替换另一个对象。
voidreset()重置将忽略已写入流的任何对象的状态。
voiduseProtocolVersion(int version)指定写入流时要使用的流协议版本。
voidwrite(byte[] buf)写入一个字节数组。
voidwrite(byte[] buf, int off, int len)写入一个子字节数组。
voidwrite(int val)写入一个字节。
voidwriteBoolean(boolean val)写入一个布尔值。
voidwriteByte(int val)写入一个 8 位字节。
voidwriteBytes(String str)将 String 作为字节序列写入。
voidwriteChar(int val)写入一个 16 位字符。
voidwriteChars(String str)将字符串写入字符序列。
protected voidwriteClassDescriptor(ObjectStreamClass desc)将指定的类描述符写入 ObjectOutputStream。
voidwriteDouble(double val)写入 64 位双精度。
voidwriteFields()将缓冲字段写入流。
voidwriteFloat(float val)写入一个 32 位浮点数。
voidwriteInt(int val)写入一个 32 位整数。
voidwriteLong(long val)写入 64 位长。
voidwriteObject(Object obj)将指定对象写入 ObjectOutputStream。
protected voidwriteObjectOverride(Object obj)子类用来覆盖默认 writeObject 方法的方法。
voidwriteShort(int val)写入 16 位短。
protected voidwriteStreamHeader()提供了 writeStreamHeader 方法,因此子类可以将自己的标头附加或前置到流中。
voidwriteUnshared(Object obj)将“非共享”对象写入 ObjectOutputStream。
voidwriteUTF(String str)以修改后的 UTF-8 格式写入此字符串的原始数据。
从类 java.lang.Object 继承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

构造函数详细信息

ObjectOutputStream

public ObjectOutputStream(OutputStream out) throws IOException

创建一个写入指定 OutputStream 的 ObjectOutputStream。 此构造函数将序列化流标头写入底层流; 调用者可能希望立即刷新流,以确保接收 ObjectInputStreams 的构造函数在读取标头时不会阻塞。

如果安装了安全管理器,则此构造函数将在由覆盖 ObjectOutputStream.putFields 或 ObjectOutputStream.writeUnshared 方法的子类的构造函数直接或间接调用时检查“enableSubclassImplementation”SerializablePermission。

参数:

参数名称参数描述
out要写入的输出流

Throws:

Throw名称Throw描述
IOException如果在写入流标头时发生 I/O 错误
SecurityException如果不受信任的子类非法覆盖安全敏感方法
NullPointerException如果 out 为空

Since:

1.4

ObjectOutputStream

protected ObjectOutputStream() throws IOException, SecurityException

为完全重新实现 ObjectOutputStream 的子类提供一种方法,使其不必分配刚刚由 ObjectOutputStream 的实现使用的私有数据。

如果安装了安全管理器,此方法首先调用安全管理器的 checkPermission 方法,并带有 SerializablePermission("enableSubclassImplementation") 权限,以确保可以启用子类化。

Throws:

Throw名称Throw描述
SecurityException如果存在安全管理器并且其 checkPermission 方法拒绝启用子类化。
IOException如果在创建此流时发生 I/O 错误

方法详情

useProtocolVersion

public void useProtocolVersion(int version) throws IOException

指定写入流时要使用的流协议版本。

此例程提供了一个挂钩,使当前版本的序列化能够以向后兼容的流格式的先前版本的格式写入。

将尽一切努力避免引入额外的向后不兼容; 但是,有时没有其他选择。

参数:

参数名称参数描述
version使用来自 java.io.ObjectStreamConstants 的 ProtocolVersion。

Throws:

Throw名称Throw描述
IllegalStateException如果在任何对象被序列化后调用。
IllegalArgumentException如果传入无效版本。
IOException如果发生 I/O 错误

Since:

1.2

writeObject

public final void writeObject(Object obj) throws IOException

将指定对象写入 ObjectOutputStream。 写入对象的类、类的签名、类的非瞬态和非静态字段的值及其所有超类型。 可以使用 writeObject 和 readObject 方法覆盖类的默认序列化。 此对象引用的对象是可传递写入的,因此可以通过 ObjectInputStream 重建对象的完整等效图。

对于 OutputStream 的问题和不应序列化的类,将引发异常。 所有异常对于 OutputStream 来说都是致命的,它处于不确定状态,由调用者来忽略或恢复流状态。

指定者:

接口 ObjectOutput 中的 writeObject

参数:

参数名称参数描述
obj要写入的对象

Throws:

Throw名称Throw描述
InvalidClassException序列化使用的类有问题。
NotSerializableException某些要序列化的对象没有实现 java.io.Serializable 接口。
IOException底层 OutputStream 引发的任何异常。

writeObjectOverride

protected void writeObjectOverride(Object obj) throws IOException

子类用来覆盖默认 writeObject 方法的方法。 此方法由使用受保护的无参数构造函数构造 ObjectInputStream 的 ObjectInputStream 的受信任子类调用。 子类应提供带有修饰符“final”的覆盖方法。

参数:

参数名称参数描述
obj要写入底层流的对象

Throws:

Throw名称Throw描述
IOException如果在写入底层流时出现 I/O 错误

Since:

1.2

writeUnshared

public void writeUnshared(Object obj) throws IOException

将“非共享”对象写入 ObjectOutputStream。 此方法与 writeObject 相同,不同之处在于它始终将给定对象作为流中新的唯一对象写入(与指向先前序列化实例的反向引用相反)。 具体来说:

  • 通过 writeUnshared 写入的对象始终以与新出现的对象(尚未写入流的对象)相同的方式序列化,无论该对象之前是否已写入。
  • 如果 writeObject 用于写入先前已使用 writeUnshared 写入的对象,则将先前的 writeUnshared 操作视为单独对象的写入。 换句话说,ObjectOutputStream 永远不会生成对通过调用 writeUnshared 写入的对象数据的反向引用。

虽然通过 writeUnshared 写入对象本身并不能保证在反序列化时对该对象的唯一引用,但它允许在流中多次定义单个对象,因此接收方对 readUnshared 的多次调用不会发生冲突。 请注意,上述规则仅适用于使用 writeUnshared 编写的基础级对象,不适用于要序列化的对象图中的任何可传递引用的子对象。

覆盖此方法的 ObjectOutputStream 子类只能在拥有“enableSubclassImplementation”SerializablePermission 的安全上下文中构造; 任何尝试在没有此权限的情况下实例化此类子类都将导致抛出 SecurityException。

参数:

参数名称参数描述
obj要写入流的对象

Throws:

Throw名称Throw没事
NotSerializableException如果图中要序列化的对象没有实现 Serializable 接口
InvalidClassException如果要序列化的对象的类存在问题
IOException如果在序列化过程中发生 I/O 错误

Since:

1.4

defaultWriteObject

public void defaultWriteObject() throws IOException

将当前类的非静态和非瞬态字段写入此流。 这只能从被序列化的类的 writeObject 方法中调用。 如果以其他方式调用它将抛出 NotActiveException。

Throws:

Throw名称Throw描述
IOException如果在写入底层 OutputStream 时发生 I/O 错误

putFields

public ObjectOutputStream.PutField putFields() throws IOException

检索用于缓冲要写入流的持久字段的对象。 当调用 writeFields 方法时,字段将被写入流。

返回:

包含可序列化字段的 Putfield 类的实例

Throws:

Throw名称Throw描述
IOException如果发生 I/O 错误

Since:

1.2

writeFields

public void writeFields() throws IOException

将缓冲字段写入流。

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误
NotActiveException当未调用类 writeObject 方法来写入对象的状态时调用。

Since:

1.2

reset

public void reset() throws IOException

重置将忽略已写入流的任何对象的状态。 状态被重置为与新的 ObjectOutputStream 相同。 流中的当前点被标记为重置,因此相应的 ObjectInputStream 将在同一点重置。 之前写入流的对象不会被称为已经在流中。 它们将再次写入流。

Throws:

Throw名称Throw描述
IOException如果在序列化对象时调用了 reset()。

annotateClass

protected void annotateClass(Class<?> cl) throws IOException

子类可以实现此方法以允许将类数据存储在流中。 默认情况下,此方法不执行任何操作。 ObjectInputStream 中对应的方法是resolveClass。 对于流中的每个唯一类,该方法只调用一次。 类名和签名将已写入流。 此方法可以免费使用 ObjectOutputStream 来保存它认为合适的类的任何表示(例如,类文件的字节)。 ObjectInputStream 对应子类中的resolveClass 方法必须读取和使用annotateClass 写入的任何数据或对象。

参数:

参数名称参数描述
cl注释自定义数据的类

Throws:

Throw名称Throw描述
IOException底层 OutputStream 引发的任何异常。

annotateProxyClass

protected void annotateProxyClass(Class<?> cl) throws IOException

子类可以实现此方法以将自定义数据与动态代理类的描述符一起存储在流中。

对于流中的每个唯一代理类描述符,该方法只调用一次。 ObjectOutputStream 中此方法的默认实现不执行任何操作。

ObjectInputStream 中对应的方法是resolveProxyClass。 对于覆盖此方法的给定 ObjectOutputStream 子类,ObjectInputStream 对应子类中的 resolveProxyClass 方法必须读取 annotateProxyClass 写入的任何数据或对象。

参数:

参数名称参数描述
cl用于注释自定义数据的代理类

Throws:

Throw名称Throw描述
IOException底层 OutputStream 抛出的任何异常

Since:

1.3

replaceObject

protected Object replaceObject(Object obj) throws IOException

此方法将允许 ObjectOutputStream 的受信任子类在序列化期间用一个对象替换另一个对象。在调用 enableReplaceObject 之前,禁用替换对象。 enableReplaceObject 方法检查请求进行替换的流是否可信。写入序列化流的每个对象的第一次出现被传递给replaceObject。对该对象的后续引用被替换为原始调用replaceObject 返回的对象。为了确保对象的私有状态不会被无意暴露,只有受信任的流可以使用 replaceObject。

ObjectOutputStream.writeObject 方法采用 Object 类型(与 Serializable 类型相反)的参数,以允许将不可序列化对象替换为可序列化对象的情况。

当子类替换对象时,它必须确保在反序列化期间必须进行补充替换,或者确保替换的对象与将存储引用的每个字段兼容。类型不是字段或数组元素类型的子类的对象通过引发异常中止序列化并且不存储该对象。

此方法仅在第一次遇到每个对象时调用一次。对该对象的所有后续引用都将重定向到新对象。此方法应返回要替换的对象或原始对象。

Null 可以作为要替换的对象返回,但可能会在包含对原始对象的引用的类中导致 NullReferenceException,因为它们可能期望一个对象而不是 null。

参数:

参数名称参数描述
obj被替换的对象

返回:

替换指定对象的替代对象

Throws:

Throw名称Throw描述
IOException底层 OutputStream 引发的任何异常。

enableReplaceObject

protected boolean enableReplaceObject(boolean enable) throws SecurityException

使流能够替换流中的对象。 启用后,将为每个正在序列化的对象调用 replaceObject 方法。

如果 enable 为 true,并且安装了安全管理器,此方法首先调用安全管理器的 checkPermission 方法,并具有 SerializablePermission("enableSubstitution") 权限,以确保可以启用流来替换流中的对象。

参数:

参数名称参数描述
enable用于启用对象替换的布尔参数

返回:

调用此方法之前的先前设置

Throws:

Throw名称Throw描述
SecurityException如果存在安全管理器并且其 checkPermission 方法拒绝启用流来替换流中的对象。

writeStreamHeader

protected void writeStreamHeader() throws IOException

提供了 writeStreamHeader 方法,因此子类可以将自己的标头附加或前置到流中。 它将幻数和版本写入流。

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeClassDescriptor

protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException

将指定的类描述符写入 ObjectOutputStream。 类描述符用于标识写入流的对象的类。 ObjectOutputStream 的子类可以重写此方法以自定义将类描述符写入序列化流的方式。 然后应该重写 ObjectInputStream 中的相应方法 readClassDescriptor 以从其自定义流表示中重构类描述符。 默认情况下,此方法根据对象序列化规范中定义的格式写入类描述符。

请注意,仅当 ObjectOutputStream 未使用旧的序列化流格式(通过调用 ObjectOutputStream 的 useProtocolVersion 方法设置)时才会调用此方法。 如果此序列化流使用旧格式 (PROTOCOL_VERSION_1),则类描述符将以无法覆盖或自定义的方式在内部写入。

参数:

参数名称参数描述
desc写入流的类描述符

Throws:

Throw名称Throw描述
IOException如果发生 I/O 错误。

Since:

1.3

write

public void write(int val) throws IOException

写入一个字节。 此方法将阻塞,直到实际写入字节。

指定者:

写入接口DataOutput

指定者:

写入接口ObjectOutput

指定者:

写在类 OutputStream

参数:

参数名称参数描述
val要写入流的字节

Throws:

Throw名称Throw描述
IOException如果发生 I/O 错误。

write

public void write(byte[] buf) throws IOException

写入一个字节数组。 此方法将阻塞,直到实际写入字节。

指定者:

写入接口DataOutput

指定者:

写入接口ObjectOutput

覆盖:

写在类 OutputStream

参数:

参数名称参数描述
buf要写入的数据

Throws:

Throw名称Throw描述
IOException如果发生 I/O 错误。

write

public void write(byte[] buf, int off, int len) throws IOException

写入一个子字节数组。

指定者:

写入接口DataOutput

指定者:

写入接口ObjectOutput

覆盖:

写在类 OutputStream

参数:

参数名称参数描述
buf要写入的数据
off数据中的起始偏移量
len写入的字节数

Throws:

Throw名称Throw描述
IOException如果发生 I/O 错误。

flush

public void flush() throws IOException

冲洗流。 这将写入任何缓冲的输出字节并刷新到底层流。

指定者:

在接口 Flushable 中刷新

指定者:

在接口 ObjectOutput 中刷新

覆盖:

类 OutputStream 中的刷新

Throws:

Throw名称Throw描述
IOException如果发生 I/O 错误。

drain

protected void drain() throws IOException

排出 ObjectOutputStream 中的所有缓冲数据。 与刷新类似,但不会将刷新传播到底层流。

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

close

public void close() throws IOException

关闭流。 必须调用此方法来释放与流关联的任何资源。

指定者:

在接口 AutoCloseable 中关闭

指定者:

在接口Closeable中关闭

指定者:

在接口 ObjectOutput 中关闭

覆盖:

在类 OutputStream 中关闭

Throws:

Throw名称Throw描述
IOException如果发生 I/O 错误。

writeBoolean

public void writeBoolean(boolean val) throws IOException

写入一个布尔值。

指定者:

接口 DataOutput 中的 writeBoolean

参数:

参数名称参数描述
val要写入的布尔值

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeByte

public void writeByte(int val) throws IOException

写入一个 8 位字节。

指定者:

接口 DataOutput 中的 writeByte

参数:

参数名称参数描述
val要写入的字节值

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeShort

public void writeShort(int val) throws IOException

写入 16 位短。

指定者:

接口 DataOutput 中的 writeShort

参数:

参数名称参数描述
val要写入的短值

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeChar

public void writeChar(int val) throws IOException

写入一个 16 位字符。

指定者:

接口 DataOutput 中的 writeChar

参数:

参数名称参数描述
val要写入的 char 值

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeInt

public void writeInt(int val) throws IOException

写入一个 32 位整数。

指定者:

接口 DataOutput 中的 writeInt

参数:

参数名称参数描述
val要写入的整数值

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeLong

public void writeLong(long val) throws IOException

写入 64 位长。

指定者:

接口 DataOutput 中的 writeLong

参数:

参数名称参数描述
val要写入的长值

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeFloat

public void writeFloat(float val) throws IOException

写入一个 32 位浮点数。

指定者:

接口 DataOutput 中的 writeFloat

参数:

参数名称参数描述
val要写入的浮点值

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeDouble

public void writeDouble(double val) throws IOException

写入 64 位双精度。

指定者:

接口 DataOutput 中的 writeDouble

参数:

参数名称参数描述
val要写入的双精度值

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeBytes

public void writeBytes(String str) throws IOException

将 String 作为字节序列写入。

指定者:

接口 DataOutput 中的 writeBytes

参数:

参数名称参数描述
str要写入的字节字符串

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeChars

public void writeChars(String str) throws IOException

将字符串写入字符序列。

指定者:

接口 DataOutput 中的 writeChars

参数:

参数名称参数描述
str要写入的字符串

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误

writeUTF

public void writeUTF(String str) throws IOException

以修改后的 UTF-8 格式写入此字符串的原始数据。 请注意,将字符串作为原始数据或作为对象写入流中存在显着差异。 writeObject 写入的 String 实例最初作为 String 写入流中。 未来的 writeObject() 调用将字符串的引用写入流中。

指定者:

接口 DataOutput 中的 writeUTF

参数:

参数名称参数描述
str要写入的字符串

Throws:

Throw名称Throw描述
IOException如果在写入底层流时发生 I/O 错误