- 所有已实现的接口:
-
Closeable,DataOutput,Flushable,ObjectOutput,ObjectStreamConstants,AutoCloseable
只有支持java.io.Serializable接口的对象才能写入流。每个可序列化对象的类都会被编码,包括类名和类的签名,对象字段和数组的值,以及从初始对象引用的任何其他对象的闭包。
方法writeObject用于将对象写入流。任何对象,包括字符串和数组,都可以使用writeObject写入。可以将多个对象或基本数据类型写入流。这些对象必须按照写入时的相同类型和顺序从相应的ObjectInputstream中读取。
也可以使用DataOutput支持的适当方法将基本数据类型写入流。也可以使用writeUTF方法写入字符串。
对象的默认序列化机制会写入对象的类、类签名以及所有非瞬态和非静态字段的值。对其他对象的引用(除了在瞬态或静态字段中)也会导致这些对象被写入。对单个对象的多个引用使用引用共享机制进行编码,以便可以将对象图还原为原始写入时的形状。
例如,要写入一个可以由ObjectInputStream中的示例读取的对象:
try (FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject("Today");
oos.writeObject(LocalDateTime.now());
} catch (Exception ex) {
// 处理异常
}
在序列化和反序列化过程中需要特殊处理的可序列化类应实现具有以下签名的方法:
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方法将各个字段写入ObjectOutputStream或使用DataOutput支持的基本数据类型方法保存状态。
序列化不会写出未实现java.io.Serializable接口的任何对象的字段。未序列化的对象的子类可以是可序列化的。在这种情况下,非可序列化类必须具有无参数构造函数,以允许初始化其字段。在这种情况下,子类有责任保存和恢复非可序列化类的状态。通常情况下,该类的字段是可访问的(公共的、包级的或受保护的),或者有可用于恢复状态的get和set方法。
通过实现writeObject和readObject方法抛出NotSerializableException可以阻止对象的序列化。ObjectOutputStream将捕获该异常并中止序列化过程。
实现Externalizable接口允许对象完全控制对象的序列化形式的内容和格式。Externalizable接口的方法writeExternal和readExternal用于保存和恢复对象的状态。当类实现这些方法时,它们可以使用ObjectOutput和ObjectInput的所有方法写入和读取自己的状态。对象有责任处理发生的任何版本更改。
枚举常量的序列化方式与普通可序列化或外部化对象不同。枚举常量的序列化形式仅包含其名称;常量的字段值不会传输。为了序列化枚举常量,ObjectOutputStream会写入常量的name方法返回的字符串。与后续出现在序列化流中的其他可序列化或外部化对象一样,枚举常量可以作为后向引用的目标。枚举类型的序列化方式无法定制;在序列化过程中,枚举类型定义的任何特定于类的writeObject和writeReplace方法都会被忽略。同样,任何serialPersistentFields或serialVersionUID字段声明也会被忽略——所有枚举类型都具有固定的serialVersionUID为0L。
除可序列化字段和外部化数据外,原始数据将以块数据记录的形式写入ObjectOutputStream。块数据记录由标头和数据组成。连续的原始数据写入将合并为一个块数据记录。块数据记录的块大小将为1024字节。每个块数据记录将填充至1024字节,或在块数据模式终止时写入。对ObjectOutputStream方法writeObject、defaultWriteObject和writeFields的调用最初会终止任何现有的块数据记录。
记录的序列化方式与普通可序列化或外部化对象不同,请参阅记录序列化。
- 自版本:
- 1.1
- 外部规范
- 参见:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic class提供对要写入ObjectOutput的持久字段的编程访问。 -
Field Summary
Fields declared in interface java.io.ObjectStreamConstants
baseWireHandle, PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, SC_BLOCK_DATA, SC_ENUM, SC_EXTERNALIZABLE, SC_SERIALIZABLE, SC_WRITE_METHOD, SERIAL_FILTER_PERMISSION, 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 -
Constructor Summary
ConstructorsModifierConstructorDescriptionprotected为完全重新实现ObjectOutputStream的子类提供一种不必为此实现分配私有数据的方法。创建一个写入指定OutputStream的ObjectOutputStream。 -
Method Summary
Modifier and TypeMethodDescriptionprotected voidannotateClass(Class<?> cl) 子类可以实现此方法以允许将类数据存储在流中。protected voidannotateProxyClass(Class<?> cl) 子类可以实现此方法,在其中将自定义数据与动态代理类的描述符一起存储在流中。voidclose()关闭流。void将当前类的非静态和非瞬态字段写入此流。protected voiddrain()清空ObjectOutputStream中的任何缓冲数据。protected booleanenableReplaceObject(boolean enable) 启用流替换写入流的对象。voidflush()刷新流。检索用于缓冲要写入流的持久字段的对象。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) 将字符串作为字节序列写入。voidwriteChar(int val) 写入一个16位字符。voidwriteChars(String str) 将字符串作为字符序列写入。protected void将指定的类描述符写入ObjectOutputStream。voidwriteDouble(double val) 写入一个64位双精度浮点数。void将缓冲字段写入流。voidwriteFloat(float val) 写入一个32位浮点数。voidwriteInt(int val) 写入一个32位整数。voidwriteLong(long val) 写入一个64位长整数。final voidwriteObject(Object obj) 将指定的对象写入ObjectOutputStream。protected void子类用于覆盖默认writeObject方法的方法。voidwriteShort(int val) 写入一个16位短整数。protected void提供writeStreamHeader方法,以便子类可以在流中附加或前置自己的标头。voidwriteUnshared(Object obj) 将“unshared”对象写入ObjectOutputStream。void以修改的UTF-8格式对此字符串进行原始数据写入。Methods declared in class java.io.OutputStream
nullOutputStream
-
Constructor Details
-
ObjectOutputStream
创建一个ObjectOutputStream,用于写入指定的OutputStream。此构造函数将序列化流头写入基础流;调用者可能希望立即刷新流,以确保接收ObjectInputStream的构造函数在读取头部时不会被阻塞。如果安装了安全管理器,则在直接或间接地由覆盖ObjectOutputStream.putFields或ObjectOutputStream.writeUnshared方法的子类的构造函数调用时,此构造函数将检查“enableSubclassImplementation”SerializablePermission。
- 参数:
-
out- 要写入的输出流 - 抛出:
-
IOException- 在写入流头时发生I/O错误时 -
SecurityException- 如果不受信任的子类非法地覆盖了安全敏感方法 -
NullPointerException- 如果out为null - 自从:
- 1.4
- 参见:
-
ObjectOutputStream
为完全重新实现ObjectOutputStream的子类提供一种方式,以避免必须分配仅由此ObjectOutputStream实现使用的私有数据。如果安装了安全管理器,此方法首先调用安全管理器的
checkPermission方法,使用SerializablePermission("enableSubclassImplementation")权限,以确保启用子类化是可以的。- 抛出:
-
SecurityException- 如果存在安全管理器并且其checkPermission方法拒绝启用子类化。 -
IOException- 在创建此流时发生I/O错误时 - 参见:
-
-
Method Details
-
useProtocolVersion
指定写入流时要使用的流协议版本。此例程提供了一个钩子,使得当前版本的Serialization能够以向后兼容的格式写入到先前版本的流格式。
将尽一切努力避免引入额外的向后不兼容性;但有时别无选择。
- 参数:
-
version- 使用java.io.ObjectStreamConstants中的ProtocolVersion。 - 抛出:
-
IllegalStateException- 如果在序列化任何对象之后调用。 -
IllegalArgumentException- 如果传入的版本无效。 -
IOException- 如果发生I/O错误 - 自从:
- 1.2
- 参见:
-
writeObject
将指定的对象写入ObjectOutputStream。对象的类、类的签名以及类的非瞬态和非静态字段的值以及其所有超类型的值都将被写入。可以使用writeObject和readObject方法覆盖类的默认序列化。此对象引用的对象将被传递写入,以便通过ObjectInputStream可以重建对象的完整等效图。对于OutputStream的问题和不应序列化的类,将抛出异常。所有异常对于OutputStream都是致命的,使其处于不确定状态,并由调用者忽略或恢复流状态。
- 指定者:
-
writeObject在接口ObjectOutput - 参数:
-
obj- 要写入的对象 - 抛出:
-
InvalidClassException- 序列化使用的类存在问题。 -
NotSerializableException- 要序列化的某个对象未实现java.io.Serializable接口。 -
IOException- 底层OutputStream抛出的任何异常。
-
writeObjectOverride
子类用于覆盖默认writeObject方法的方法。这个方法由使用受保护的无参数构造函数构造ObjectOutputStream的ObjectOutputStream的受信任的子类调用。预期子类提供一个带有修饰符“final”的覆盖方法。- 参数:
-
obj- 要写入到基础流的对象 - 抛出:
-
IOException- 在写入到基础流时发生I/O错误时 - 自从:
- 1.2
- 参见:
-
defaultWriteObject
将当前类的非静态和非瞬态字段写入此流。只能从正在序列化的类的writeObject方法中调用此方法。否则,如果调用它,将抛出NotActiveException。- 抛出:
-
IOException- 在写入到基础OutputStream时发生I/O错误时
-
putFields
检索用于缓冲要写入流的持久字段的对象。在调用writeFields方法时,这些字段将被写入流。- 返回:
- 一个持有可序列化字段的Putfield类的实例
- 抛出:
-
IOException- 如果发生I/O错误 - 自从:
- 1.2
-
writeFields
将缓冲字段写入流。- 抛出:
-
IOException- 在写入到基础流时发生I/O错误时 -
NotActiveException- 当类的writeObject方法未被调用以写入对象的状态时调用。 - 自从:
- 1.2
-
reset
重置将忽略已写入流的任何对象的状态。状态将重置为与新ObjectOutputStream相同。流中的当前点被标记为重置,因此相应的ObjectInputStream将在相同点重置。先前写入流的对象将不会被视为已经在流中。它们将再次写入流。- 抛出:
-
IOException- 如果在序列化对象时调用reset()。
-
annotateClass
子类可以实现此方法,以允许将类数据存储在流中。默认情况下,此方法不执行任何操作。ObjectInputStream中对应的方法是resolveClass。对于流中的每个唯一类,此方法将被调用一次。类名和签名已经写入流中。此方法可以自由使用ObjectOutputStream来保存其认为合适的类的任何表示(例如,类文件的字节)。ObjectInputStream中对应的resolveClass方法必须读取并使用annotateClass写入的任何数据或对象。- 参数:
-
cl- 要为其注释自定义数据的类 - 抛出:
-
IOException- 由底层OutputStream抛出的任何异常。
-
annotateProxyClass
子类可以实现此方法,以在流中存储自定义数据以及动态代理类的描述符。对于流中的每个唯一代理类描述符,将调用此方法一次。ObjectOutputStream中此方法的默认实现不执行任何操作。
ObjectInputStream中对应的方法是resolveProxyClass。对于覆盖此方法的ObjectOutputStream的子类,ObjectInputStream中对应的resolveProxyClass方法必须读取annotateProxyClass写入的任何数据或对象。
- 参数:
-
cl- 要为其注释自定义数据的代理类 - 抛出:
-
IOException- 由底层OutputStream抛出的任何异常。 - 自 JDK 版本:
- 1.3
- 参见:
-
replaceObject
此方法允许ObjectOutputStream的受信任子类在序列化期间替换一个对象为另一个对象。只有在调用enableReplaceObject之后才启用替换对象。enableReplaceObject方法检查请求执行替换的流是否可信任。将每个写入序列化流的对象的第一次出现传递给replaceObject。对对象的后续引用将被替换为原始调用replaceObject返回的对象。为确保对象的私有状态不会被意外暴露,只有受信任的流可以使用replaceObject。ObjectOutputStream.writeObject方法接受Object类型的参数(而不是Serializable类型),以允许在非可序列化对象被可序列化对象替换的情况下使用。
当子类替换对象时,必须确保在反序列化期间进行补充替换,或者替换的对象与引用将被存储的每个字段兼容。类型不是字段或数组元素类型的子类的对象会通过引发异常中止序列化,并且对象不会被存储。
此方法仅在首次遇到每个对象时调用一次。所有后续对该对象的引用将重定向到新对象。此方法应返回要替换的对象或原始对象。
可以返回null作为要替换的对象,但可能会导致包含对原始对象的引用的类抛出
NullPointerException,因为它们可能期望一个对象而不是null。- 参数:
-
obj- 要替换的对象 - 返回:
- 替换指定对象的替代对象
- 抛出:
-
IOException- 由底层OutputStream抛出的任何异常。
-
enableReplaceObject
启用流以替换写入流的对象。启用后,将为每个被序列化的对象调用replaceObject方法。如果当前未启用对象替换,并且enable为true,并且已安装安全管理器,则此方法首先调用安全管理器的checkPermission方法,使用SerializablePermission("enableSubstitution")权限来确保调用者被允许启用流以替换写入流的对象。
- 参数:
-
enable- 为每个被序列化的对象启用replaceObject的使用时为true - 返回:
- 在调用此方法之前的先前设置
- 抛出:
-
SecurityException- 如果存在安全管理器并且其checkPermission方法拒绝启用流以替换写入流的对象。 - 参见:
-
writeStreamHeader
writeStreamHeader方法提供给子类,以便在流中附加或前置自己的头部。它向流中写入魔数和版本号。- 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeClassDescriptor
将指定的类描述符写入ObjectOutputStream。类描述符用于标识写入流中的对象的类。ObjectOutputStream的子类可以重写此方法,以自定义写入序列化流中的类描述符的方式。ObjectInputStream中的对应方法readClassDescriptor应该被重写,以从其自定义流表示中重建类描述符。默认情况下,此方法根据《Java对象序列化规范》中定义的格式写入类描述符。请注意,仅当ObjectOutputStream未使用旧的序列化流格式(通过调用ObjectOutputStream的useProtocolVersion方法设置)时,才会调用此方法。如果此序列化流使用旧格式(PROTOCOL_VERSION_1),则类描述符将以无法被覆盖或自定义的方式内部写入。
- 参数:
-
desc- 要写入流中的类描述符 - 抛出:
-
IOException- 如果发生I/O错误。 - 自 JDK 版本:
- 1.3
- 外部规范
- 参见:
-
write
写入一个字节。此方法将阻塞,直到字节实际被写入。- 在接口中指定为:
-
writein interfaceDataOutput - 在接口中指定为:
-
writein interfaceObjectOutput - 在类中指定为:
-
writein classOutputStream - 参数:
-
val- 要写入流中的字节 - 抛出:
-
IOException- 如果发生I/O错误。
-
write
写入字节数组。此方法将阻塞,直到字节实际被写入。- 在接口中指定为:
-
writein interfaceDataOutput - 在接口中指定为:
-
writein interfaceObjectOutput - 在类中覆盖为:
-
writein classOutputStream - 参数:
-
buf- 要写入的数据 - 抛出:
-
IOException- 如果发生I/O错误。 - 参见:
-
write
写入字节数组的子数组。- 指定者:
-
write在接口DataOutput中 - 指定者:
-
write在接口ObjectOutput中 - 覆盖:
-
write在类OutputStream中 - 参数:
-
buf- 要写入的数据 -
off- 数据中的起始偏移量 -
len- 要写入的字节数 - 抛出:
-
IOException- 如果发生I/O错误。特别地,如果输出流已关闭,则会抛出IOException。 -
IndexOutOfBoundsException- 如果off为负、len为负或len大于b.length - off
-
flush
刷新流。这将写入任何缓冲的输出字节并刷新到底层流。- 指定者:
-
flush在接口Flushable中 - 指定者:
-
flush在接口ObjectOutput中 - 覆盖:
-
flush在类OutputStream中 - 抛出:
-
IOException- 如果发生I/O错误。
-
drain
清空ObjectOutputStream中的任何缓冲数据。类似于flush,但不会将刷新传播到底层流。- 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
close
关闭流。必须调用此方法以释放与流关联的任何资源。- 指定者:
-
close在接口AutoCloseable中 - 指定者:
-
close在接口Closeable中 - 指定者:
-
close在接口ObjectOutput中 - 覆盖:
-
close在类OutputStream中 - 抛出:
-
IOException- 如果发生I/O错误。
-
writeBoolean
写入一个布尔值。- 指定者:
-
writeBoolean在接口DataOutput中 - 参数:
-
val- 要写入的布尔值 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeByte
写入一个8位字节。- 指定者:
-
writeByte在接口DataOutput中 - 参数:
-
val- 要写入的字节值 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeShort
写入一个16位短整数。- 指定者:
-
writeShort在接口DataOutput中 - 参数:
-
val- 要写入的短整数值 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeChar
写入一个16位字符。- 指定者:
-
writeChar在接口DataOutput中 - 参数:
-
val- 要写入的字符值 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeInt
写入一个32位整数。- 指定者:
-
writeInt在接口DataOutput中 - 参数:
-
val- 要写入的整数值 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeLong
写入一个64位长整数。- 指定者:
-
writeLong在接口DataOutput中 - 参数:
-
val- 要写入的长整数值 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeFloat
写入一个32位浮点数。- 指定者:
-
writeFloat在接口DataOutput中 - 参数:
-
val- 要写入的浮点数值 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeDouble
写入一个64位双精度浮点数。- 指定者:
-
writeDouble在接口DataOutput中 - 参数:
-
val- 要写入的双精度浮点数值 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeBytes
将字符串作为字节序列写入。- 指定者:
-
writeBytes在接口DataOutput中 - 参数:
-
str- 要写入的字节字符串 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeChars
将字符串作为字符序列写入。- 指定者:
-
writeChars在接口DataOutput中 - 参数:
-
str- 要写入的字符字符串 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-
writeUTF
以修改后的UTF-8格式对此字符串进行原始数据写入。请注意,在将字符串作为原始数据或对象写入流中存在重大差异。通过writeObject写入的字符串实例最初作为字符串写入流中。将来的writeObject()调用将引用写入流中的字符串。- 指定者:
-
writeUTF在接口DataOutput中 - 参数:
-
str- 要写入的字符串 - 抛出:
-
IOException- 如果在写入到底层流时发生I/O错误
-