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接口的对象的字段。 ​不可序列化的对象的子类可以是可序列化的。 在这种情况下,非可序列化类必须有一个无参数构造函数,以允许其字段被初始化。 在这种情况下,子类有责任保存并恢复不可序列化类的状态。 通常情况下,该类的字段是可访问的(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最初终止任何现有的块数据记录。

 构造方法

类型

构造方法和描述

​protected ​

​ObjectOutputStream​​()​

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


​ObjectOutputStream​​(​​OutputStream​​ out)​

创建一个写入指定的OutputStream的ObjectOutputStream。


方法

类型和参数

方法和描述

​protected void​

​annotateClass​​(​​类​​<?> cl)​

子类可以实现此方法,以允许类数据存储在流中。


​protected void​

​annotateProxyClass​​(​​类​​<?> cl)​

子类可以实现这种方法来存储流中的自定义数据以及动态代理类的描述符。


​void​

​close​​()​

关闭流。


​void​

​defaultWriteObject​​()​

将当前类的非静态和非瞬态字段写入此流。


​protected void​

​drain​​()​

排除ObjectOutputStream中的缓冲数据。


​protected boolean​

​enableReplaceObject​​(boolean enable)​

启用流来替换流中的对象。


​void​

​flush​​()​

刷新流。


​ObjectOutputStream.PutField​

​putFields​​()​

检索用于缓冲要写入流的持久性字段的对象。


​protected ​​Object​

​replaceObject​​(​​Object​​ obj)​

该方法将允许ObjectOutputStream的可信子类在序列化期间将一个对象替换为另一个对象。


​void​

​reset​​()​

复位将忽略已写入流的任何对象的状态。


​void​

​useProtocolVersion​​(int version)​

指定在编写流时使用的流协议版本。


​void​

​write​​(byte[] buf)​

写入一个字节数组。


​void​

​write​​(byte[] buf, int off, int len)​

写入一个子字节数组。


​void​

​write​​(int val)​

写一个字节。


​void​

​writeBoolean​​(boolean val)​

写一个布尔值。


​void​

​writeByte​​(int val)​

写入一个8位字节。


​void​

​writeBytes​​(​​String​​ str)​

写一个字符串作为字节序列。


​void​

​writeChar​​(int val)​

写一个16位的字符。


​void​

​writeChars​​(​​String​​ str)​

写一个字符串作为一系列的字符。


​protected void​

​writeClassDescriptor​​(​​ObjectStreamClass​​ desc)​

将指定的类描述符写入ObjectOutputStream。


​void​

​writeDouble​​(double val)​

写一个64位的双倍。


​void​

​writeFields​​()​

将缓冲的字段写入流。


​void​

​writeFloat​​(float val)​

写一个32位浮点数。


​void​

​writeInt​​(int val)​

写一个32位int。


​void​

​writeLong​​(long val)​

写一个64位长


​void​

​writeObject​​(​​Object​​ obj)​

将指定的对象写入ObjectOutputStream。


​protected void​

​writeObjectOverride​​(​​Object​​ obj)​

子类使用的方法来覆盖默认的writeObject方法。


​void​

​writeShort​​(int val)​

写一个16位短。


​protected void​

​writeStreamHeader​​()​

提供了writeStreamHeader方法,因此子类可以在流中附加或预先添加自己的头。


​void​

​writeUnshared​​(​​Object​​ obj)​

将“非共享”对象写入ObjectOutputStream。


​void​

​writeUTF​​(​​String​​ str)​

此字符串的原始数据写入格式为 ​​modified UTF-8​​ 。


ObjectInputStream

public class ObjectInputStream
extends InputStream
implements ObjectInput, ObjectStreamConstants

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接口允许对象序列化保存和恢复对象的整个状态,并允许类在流被写入的时间和读取时间之间演变。 它自动遍历对象之间的引用,保存和恢复整个图形。

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

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方法写入的自定义数据边界的对象数据将导致使用eof字段值为true的抛出OptionalDataException。 超过分配数据结束的非对象读取将以与指示流结尾相同的方式反映数据的结尾:Bytewise读取将返回-1作为字节读取或读取的字节数,并且原语读取将抛出EOFExceptions。 如果没有相应的writeObject方法,则默认序列化数据的结尾标记分配的数据的结尾。

在readExternal方法中发出的原始和对象读取调用的行为方式相同 - 如果流已经位于由相应的writeExternal方法写入的数据的末尾,则对象读取会将可选数据异常与eof设置为true,Bytewise读取将返回-1,并且原始读取将抛出EOFExceptions。 请注意,此行为对于使用旧的​​ObjectStreamConstants.PROTOCOL_VERSION_1​​协议编写的流不适用,其中由writeExternal方法写入的数据的结尾未划分,因此无法检测。

如果序列化流未将给定类列为反序列化对象的超类,则readObjectNoData方法负责初始化其特定类的对象的状态。 这可能发生在接收方使用与发送方不同的反序列化实例的类的版本的情况下,并且接收者的版本扩展了不被发送者版本扩展的类。 如果序列化流已被篡改,也可能发生这种情况; 因此,尽管存在“敌对”或不完整的源流,readObjectNoData可用于正确初始化反序列化对象。

序列化不会读取或赋值任何不实现java.io.Serializable接口的对象的值。 不可序列化的对象的子类可以是可序列化的。 在这种情况下,非可序列化类必须有一个无参数构造函数,以允许其字段被初始化。 在这种情况下,子类有责任保存并恢复不可序列化类的状态。 通常情况下,该类的字段是可访问的(public,package或protected),或者可以使用get和set方法来恢复状态。

反序列化对象时发生的任何异常都将被ObjectInputStream捕获并中止读取过程。

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

枚举常数的反序列化与普通可序列化或外部化对象不同。 枚举常数的序列化形式仅由其名称组成; 不传输常数的字段值。 要反序列化枚举常量,ObjectInputStream从流中读取常量名称; 然后通过使用枚举常量的基本类型和接收的常量名称作为参数调用静态方法​​Enum.valueOf(Class, String)​​获得反序列化常数。 像其他可序列化或可外部化的对象一样,枚举常量可以作为随后在序列化流中出现的反向引用的目标。 枚举常量被反序列化的过程无法自定义:在反序列化期间将忽略由枚举类型定义的任何特定于类的readObject,readObjectNoData和readResolve方法。 类似地,任何serialPersistentFields或serialVersionUID字段声明也被忽略 - 所有枚举类型都有一个固定的serialVersionUID为0L。

构造方法

类型

构造方法和描述

​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)​

读入一个字节数组。


​boolean​

​readBoolean​​()​

读取布尔值。


​byte​

​readByte​​()​

读取一个8位字节。


​char​

​readChar​​()​

读一个16位字符。


​protected ​​ObjectStreamClass​

​readClassDescriptor​​()​

从序列化流读取类描述符。


​double​

​readDouble​​()​

读64位双倍。


​ObjectInputStream.GetField​

​readFields​​()​

从流中读取持久性字段,并通过名称获取它们。


​float​

​readFloat​​()​

读32位浮点数。


​void​

​readFully​​(byte[] buf)​

读取字节,阻塞直到读取所有字节。


​void​

​readFully​​(byte[] buf, int off, int len)​

读取字节,阻塞直到读取所有字节。


​int​

​readInt​​()​

读取一个32位int。


​long​

​readLong​​()​

读64位长。


​Object​

​readObject​​()​

从ObjectInputStream读取一个对象。


​protected ​​Object​

​readObjectOverride​​()​

此方法由ObjectOutputStream的受信任子类调用,该子类使用受保护的无参构造函数构造ObjectOutputStream。


​short​

​readShort​​()​

读取16位短。


​protected void​

​readStreamHeader​​()​

提供了readStreamHeader方法来允许子类读取和验证自己的流标题。


​Object​

​readUnshared​​()​

从ObjectInputStream读取一个“非共享”对象。


​int​

​readUnsignedByte​​()​

读取一个无符号的8位字节。


​int​

​readUnsignedShort​​()​

读取无符号16位短。


​String​

​readUTF​​()​

以 ​​modified UTF-8​​格式读取字符串。


​void​

​registerValidation​​(​​ObjectInputValidation​​ obj, int prio)​

在返回图之前注册要验证的对象。


​protected ​​类​​<?>​

​resolveClass​​(​​ObjectStreamClass​​ desc)​

加载本地类等效的指定流类描述。


​protected ​​Object​

​resolveObject​​(​​Object​​ obj)​

此方法将允许ObjectInputStream的受信任子类在反序列化期间将一个对象替换为另一个对象。


​protected ​​类​​<?>​

​resolveProxyClass​​(​​String​​[] interfaces)​

返回一个代理类,它实现代理类描述符中命名的接口; 子类可以实现此方法从流中读取自定义数据以及动态代理类的描述符,从而允许它们为接口和代理类使用备用加载机制。


​int​

​skipBytes​​(int len)​

跳过字节。


例如

package com.test;

import java.io.*;

public class Main10 {
private static final long serialVersionUID = 423758L;
public static void main(String[] args) throws IOException, ClassNotFoundException {


File file = new File("config-mybatis/1/44");
FileOutputStream fileOutputStream = new FileOutputStream(file);
//序列化
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject("这是44.txt文件");
objectOutputStream.flush();
objectOutputStream.close();

FileInputStream fileInputStream = new FileInputStream(file);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
String string = (String) objectInputStream.readObject();
objectInputStream.close();
System.out.println(string);

FileOutputStream fileOutputStream1 = new FileOutputStream("config-mybatis/1/6.html");
ObjectOutputStream objectOutputStream1 = new ObjectOutputStream(fileOutputStream1);
objectOutputStream1.writeObject("这是66.HTML");
objectOutputStream1.flush();
objectOutputStream1.close();

}
}