Module java.base
Package java.io

Class 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) {
         // 处理异常
     }

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

    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
外部规范
参见:
  • Constructor Details

    • ObjectOutputStream

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

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

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

      protected ObjectOutputStream() throws IOException, SecurityException
      为完全重新实现ObjectOutputStream的子类提供一种方式,以避免必须分配仅由此ObjectOutputStream实现使用的私有数据。

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

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

    • useProtocolVersion

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

      此例程提供了一个钩子,使得当前版本的Serialization能够以向后兼容的格式写入到先前版本的流格式。

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

      参数:
      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
      将“unshared”对象写入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抛出的任何异常。
      自 JDK 版本:
      1.3
      参见:
    • replaceObject

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

      ObjectOutputStream.writeObject方法接受Object类型的参数(而不是Serializable类型),以允许在非可序列化对象被可序列化对象替换的情况下使用。

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

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

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

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

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

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

      参数:
      enable - 为每个被序列化的对象启用replaceObject的使用时为true
      返回:
      在调用此方法之前的先前设置
      抛出:
      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错误。
      自 JDK 版本:
      1.3
      外部规范
      参见:
    • write

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

      public void write(byte[] buf) throws IOException
      写入字节数组。此方法将阻塞,直到字节实际被写入。
      在接口中指定为:
      write in interface DataOutput
      在接口中指定为:
      write in interface ObjectOutput
      在类中覆盖为:
      write in class 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,但不会将刷新传播到底层流。
      抛出:
      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
      写入一个布尔值。
      指定者:
      writeBoolean 在接口 DataOutput
      参数:
      val - 要写入的布尔值
      抛出:
      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位整数。
      指定者:
      writeInt 在接口 DataOutput
      参数:
      val - 要写入的整数值
      抛出:
      IOException - 如果在写入到底层流时发生I/O错误
    • writeLong

      public void writeLong(long val) throws IOException
      写入一个64位长整数。
      指定者:
      writeLong 在接口 DataOutput
      参数:
      val - 要写入的长整数值
      抛出:
      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
      将字符串作为字节序列写入。
      指定者:
      writeBytes 在接口 DataOutput
      参数:
      str - 要写入的字节字符串
      抛出:
      IOException - 如果在写入到底层流时发生I/O错误
    • writeChars

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

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