模块 java.base
 java.io

类 ObjectOutputStream

java.lang.Object
java.io.OutputStream
java.io.ObjectOutputStream
所有已实现的接口:
Closeable , DataOutput , Flushable , ObjectOutput , ObjectStreamConstants , AutoCloseable

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

只有支持 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) {
     // handle exception
   }
 

在序列化和反序列化过程中需要特殊处理的可序列化类应该实现具有以下签名的方法:

  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 接口的对象的字段。不可序列化的对象的子类可以是可序列化的。在这种情况下,不可序列化的类必须有一个无参数的构造方法来允许初始化它的字段。在这种情况下,子类有责任保存和恢复不可序列化类的状态。通常情况下,该类的字段是可访问的(public、package 或 protected),或者存在可用于恢复状态的 get 和 set 方法。

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

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

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

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

记录的序列化方式不同于普通的可序列化或可外部化的对象,请参阅 记录序列化

自从:
1.1
参见:
  • 构造方法详细信息

    • ObjectOutputStream

      public ObjectOutputStream(OutputStream  out) throws IOException
      创建一个写入指定 OutputStream 的 ObjectOutputStream。此构造方法将序列化流标头写入基础流;调用者可能希望立即刷新流以确保用于接收 ObjectInputStreams 的构造方法在读取标头时不会阻塞。

      重写 ObjectOutputStream.putFields 或 ObjectOutputStream.writeUnshared 方法的子类的构造方法直接或间接调用时,此构造方法将检查“enableSubclassImplementation”SerializablePermission 。

      参数:
      out - 要写入的输出流
      抛出:
      IOException - 如果在写入流头时发生 I/O 错误
      SecurityException - 如果不受信任的子类非法覆盖安全敏感方法
      NullPointerException - 如果 outnull
      自从:
      1.4
      参见:
    • ObjectOutputStream

      protected ObjectOutputStream() throws IOException , SecurityException
      为完全重新实现 ObjectOutputStream 的子类提供一种方法,使其不必分配仅由该 ObjectOutputStream 实现使用的私有数据。

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

      抛出:
      SecurityException - 如果安全管理器存在且其 checkPermission 方法拒绝启用子类化。
      IOException - 如果在创建此流时发生 I/O 错误
      参见:
  • 方法详情

    • useProtocolVersion

      public void useProtocolVersion(int version) throws IOException
      指定写入流时要使用的流协议版本。

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

      将尽一切努力避免引入额外的向后不兼容性;然而,有时别无选择。

      参数:
      version - 使用来自 java.io.ObjectStreamConstants 的 ProtocolVersion。
      抛出:
      IllegalStateException - 如果在任何对象被序列化后调用。
      IllegalArgumentException - 如果传入的版本无效。
      IOException - 如果发生 I/O 错误
      自从:
      1.2
      参见:
    • writeObject

      public final void writeObject(Object  obj) throws IOException
      将指定对象写入 ObjectOutputStream。对象的类、类的签名以及类及其所有超类型的非瞬态和非静态字段的值都被写入。可以使用 writeObject 和 readObject 方法重写类的默认序列化。此对象引用的对象被传递地写入,以便可以通过 ObjectInputStream 重建对象的完整等效图。

      OutputStream 问题和不应序列化的类会抛出异常。所有异常对于处于不确定状态的 OutputStream 都是致命的,并且由调用者忽略或恢复流状态。

      指定者:
      writeObject 在接口 ObjectOutput
      参数:
      obj - 要写入的对象
      抛出:
      InvalidClassException - 序列化使用的类有问题。
      NotSerializableException - 某些要序列化的对象未实现 java.io.Serializable 接口。
      IOException - 底层 OutputStream 抛出的任何异常。
    • writeObjectOverride

      protected void writeObjectOverride(Object  obj) throws IOException
      子类用于重写默认 writeObject 方法的方法。此方法由使用受保护的无参数构造方法构造 ObjectOutputStream 的 ObjectOutputStream 的受信任子类调用。子类应提供带有修饰符“final”的重写方法。
      参数:
      obj - 要写入底层流的对象
      抛出:
      IOException - 如果写入底层流时出现 I/O 错误
      自从:
      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 - 写入流的对象
      抛出:
      NotSerializableException - 如果要序列化的图中的对象未实现 Serializable 接口
      InvalidClassException - 如果要序列化的对象的类存在问题
      IOException - 如果在序列化期间发生 I/O 错误
      自从:
      1.4
    • defaultWriteObject

      public void defaultWriteObject() throws IOException
      将当前类的非静态和非瞬态字段写入此流。这只能从正在序列化的类的 writeObject 方法中调用。如果以其他方式调用,它将抛出 NotActiveException。
      抛出:
      IOException - 如果在写入底层 OutputStream 时发生 I/O 错误
    • putFields

      public ObjectOutputStream.PutField  putFields() throws IOException
      检索用于缓冲要写入流的持久字段的对象。当调用 writeFields 方法时,字段将被写入流。
      返回:
      包含可序列化字段的类 Putfield 的实例
      抛出:
      IOException - 如果发生 I/O 错误
      自从:
      1.2
    • writeFields

      public void writeFields() throws IOException
      将缓冲字段写入流。
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
      NotActiveException - 在未调用类 writeObject 方法写入对象状态时调用。
      自从:
      1.2
    • reset

      public void reset() throws IOException
      重置将忽略已写入流的任何对象的状态。状态重置为与新的 ObjectOutputStream 相同。流中的当前点被标记为重置,因此相应的 ObjectInputStream 将在同一点重置。先前写入流的对象将不会被称为已经在流中。它们将再次写入流中。
      抛出:
      IOException - 如果在序列化对象时调用了 reset()。
    • annotateClass

      protected void annotateClass(Class <?> cl) throws IOException
      子类可以实现此方法以允许将类数据存储在流中。默认情况下,此方法不执行任何操作。 ObjectInputStream中对应的方法是resolveClass。对于流中的每个唯一类,此方法只调用一次。类名和签名将已经写入流中。此方法可以自由使用 ObjectOutputStream 来保存它认为合适的类的任何表示(例如,类文件的字节)。 ObjectInputStream对应子类中的resolveClass方法必须读取和使用annotateClass写入的任何数据或对象。
      参数:
      cl - 为其注释自定义数据的类
      抛出:
      IOException - 底层 OutputStream 抛出的任何异常。
    • annotateProxyClass

      protected void annotateProxyClass(Class <?> cl) throws IOException
      子类可以实现此方法以将自定义数据与动态代理类的描述符一起存储在流中。

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

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

      参数:
      cl - 用于注释自定义数据的代理类
      抛出:
      IOException - 底层 OutputStream 抛出的任何异常
      自从:
      1.3
      参见:
    • replaceObject

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

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

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

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

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

      参数:
      obj - 要替换的对象
      返回:
      替换指定对象的替代对象
      抛出:
      IOException - 底层 OutputStream 抛出的任何异常。
    • enableReplaceObject

      protected boolean enableReplaceObject(boolean enable) throws SecurityException
      使流能够替换写入流的对象。启用后,将为每个被序列化的对象调用 replaceObject(java.lang.Object) 方法。

      如果当前未启用对象替换,并且enable为真,并且安装了安全管理器,则此方法首先以SerializablePermission("enableSubstitution")权限调用安全管理器的checkPermission方法,以确保允许调用者启用流来进行对象替换写入流。

      参数:
      enable - 为每个被序列化的对象启用 replaceObject 时为真
      返回:
      调用此方法之前的先前设置
      抛出:
      SecurityException - 如果安全管理器存在且其 checkPermission 方法拒绝启用流来替换写入流的对象。
      参见:
    • writeStreamHeader

      protected void writeStreamHeader() throws IOException
      提供了 writeStreamHeader 方法,因此子类可以将自己的标头附加或添加到流中。它将幻数和版本写入流。
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeClassDescriptor

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

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

      参数:
      desc - 写入流的类描述符
      抛出:
      IOException - 如果发生 I/O 错误。
      自从:
      1.3
      参见:
    • write

      public void write(int val) throws IOException
      写入一个字节。此方法将阻塞,直到实际写入字节为止。
      指定者:
      write 在接口 DataOutput
      指定者:
      write 在接口 ObjectOutput
      指定者:
      write 在类 OutputStream
      参数:
      val - 要写入流的字节
      抛出:
      IOException - 如果发生 I/O 错误。
    • write

      public void write(byte[] buf) throws IOException
      写入一个字节数组。此方法将阻塞,直到实际写入字节为止。
      指定者:
      write 在接口 DataOutput
      指定者:
      write 在接口 ObjectOutput
      重写:
      write 在类 OutputStream
      参数:
      buf - 要写入的数据
      抛出:
      IOException - 如果发生 I/O 错误。
      参见:
    • write

      public void write(byte[] buf, int off, int len) throws IOException
      写入一个字节子数组。
      指定者:
      write 在接口 DataOutput
      指定者:
      write 在接口 ObjectOutput
      重写:
      write 在类 OutputStream
      参数:
      buf - 要写入的数据
      off - 数据中的起始偏移量
      len - 写入的字节数
      抛出:
      IOException - 如果发生 I/O 错误。特别是,如果输出流关闭,则会抛出 IOException
      IndexOutOfBoundsException - 如果 off 为负,len 为负,或者 len 大于 b.length - off
    • flush

      public void flush() throws IOException
      冲洗流。这将写入任何缓冲的输出字节并刷新到底层流。
      指定者:
      flush 在接口 Flushable
      指定者:
      flush 在接口 ObjectOutput
      重写:
      flush 在类 OutputStream
      抛出:
      IOException - 如果发生 I/O 错误。
    • drain

      protected void drain() throws IOException
      清空 ObjectOutputStream 中的所有缓冲数据。与 flush 类似,但不会将 flush 传播到底层流。
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • close

      public void close() throws IOException
      关闭流。必须调用此方法来释放与流关联的任何资源。
      指定者:
      close 在接口 AutoCloseable
      指定者:
      close 在接口 Closeable
      指定者:
      close 在接口 ObjectOutput
      重写:
      close 在类 OutputStream
      抛出:
      IOException - 如果发生 I/O 错误。
    • writeBoolean

      public void writeBoolean(boolean val) throws IOException
      写入一个boolean。
      指定者:
      writeBoolean 在接口 DataOutput
      参数:
      val - 要写入的boolean
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeByte

      public void writeByte(int val) throws IOException
      写入一个 8 位字节。
      指定者:
      writeByte 在接口 DataOutput
      参数:
      val - 要写入的字节值
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeShort

      public void writeShort(int val) throws IOException
      写一个 16 位短。
      指定者:
      writeShort 在接口 DataOutput
      参数:
      val - 要写入的短值
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeChar

      public void writeChar(int val) throws IOException
      写入 16 位字符。
      指定者:
      writeChar 在接口 DataOutput
      参数:
      val - 要写入的字符值
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeInt

      public void writeInt(int val) throws IOException
      写入 32 位 int。
      指定者:
      writeInt 在接口 DataOutput
      参数:
      val - 要写入的整数值
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeLong

      public void writeLong(long val) throws IOException
      写入 64 位长。
      指定者:
      writeLong 在接口 DataOutput
      参数:
      val - 要写入的 long 值
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeFloat

      public void writeFloat(float val) throws IOException
      写入 32 位浮点数。
      指定者:
      writeFloat 在接口 DataOutput
      参数:
      val - 要写入的浮点值
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeDouble

      public void writeDouble(double val) throws IOException
      写入 64 位双精度数。
      指定者:
      writeDouble 在接口 DataOutput
      参数:
      val - 要写入的双精度值
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeBytes

      public void writeBytes(String  str) throws IOException
      将 String 作为字节序列写入。
      指定者:
      writeBytes 在接口 DataOutput
      参数:
      str - 要写入的字节串
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeChars

      public void writeChars(String  str) throws IOException
      将 String 作为字符序列写入。
      指定者:
      writeChars 在接口 DataOutput
      参数:
      str - 要写入的字符串
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误
    • writeUTF

      public void writeUTF(String  str) throws IOException
      修改后的 UTF-8 格式写入此字符串的原始数据。请注意,将字符串作为原始数据或作为对象写入流中存在显着差异。 writeObject 写入的 String 实例最初作为 String 写入流中。未来的 writeObject() 调用将对字符串的引用写入流中。
      指定者:
      writeUTF 在接口 DataOutput
      参数:
      str - 要写入的字符串
      抛出:
      IOException - 如果在写入底层流时发生 I/O 错误