Most visited

Recently visited

Added in API level 1

Serializable

public interface Serializable

java.io.Serializable


类的可序列化由实现java.io.Serializable接口的类启用。 没有实现这个接口的类将不会有任何状态序列化或反序列化。 可序列化类的所有子类本身都是可序列化的。 序列化接口没有方法或字段,仅用于识别可序列化的语义。

为了允许不可序列化的类的子类被序列化,子类可以承担保存和恢复超类型的公共,受保护和(如果可访问的)包字段的状态的责任。 只有当它继承的类有一个可访问的无参数构造函数来初始化类的状态时,该子类才可以承担这个责任。 如果不是这种情况,则声明一个类Serializable是错误的。 该错误将在运行时检测到。

在反序列化过程中,不可序列化的类的字段将使用该类的public或protected no-arg构造函数初始化。 一个无参数的构造函数必须可以访问可序列化的子类。 序列化子类的字段将从流中恢复。

遍历图时,可能遇到不支持Serializable接口的对象。 在这种情况下,NotSerializableException将被抛出,并将标识不可序列化的对象的类。

在序列化和反序列化过程中需要特殊处理的类必须实现具有以下精确特征的特殊方法:

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

writeObject方法负责为其特定类编写对象的状态,以便相应的readObject方法可以恢复它。 通过调用out.defaultWriteObject可以调用保存对象字段的默认机制。 该方法不需要关注属于其超类或亚类的状态。 状态通过使用writeObject方法将单个字段写入ObjectOutputStream或使用DataOutput支持的基本数据类型的方法来保存。

readObject方法负责从流中读取数据并恢复类字段。 它可能会调用in.defaultReadObject来调用默认机制来恢复对象的非静态和非瞬态字段。 defaultReadObject方法使用流中的信息将流中保存的对象的字段与当前对象中相应命名的字段进行分配。 当类已经发展为添加新字段时,这将处理这种情况。 该方法不需要关注属于其超类或亚类的状态。 状态通过使用writeObject方法将单个字段写入ObjectOutputStream或使用DataOutput支持的基本数据类型的方法来保存。

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

在将对象写入流时需要指定可供使用的替代对象的可序列化类应实现具有确切签名的特殊方法:

 ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
 

如果该方法存在并且可以通过序列化对象的类中定义的方法访问,则此序列化将调用此writeReplace方法。 因此,该方法可以具有私人的,受保护的和包私人访问。 这个方法的子类访问遵循java可访问性规则。

当从流中读取实例的时候,需要指定替换的类应该实现具有确切签名的特殊方法。

 ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
 

这个readResolve方法遵循与writeReplace相同的调用规则和可访问性规则。

序列化运行时与每个可序列化类关联一个称为serialVersionUID的版本号,在反序列化过程中使用该版本号来验证序列化对象的发送者和接收者是否已加载该对象的与序列化相容的类。 如果接收者已经为具有与相应的发送者类不同的serialVersionUID的对象加载了类,那么反序列化将导致InvalidClassException 一个可序列化的类可以通过声明一个名为"serialVersionUID"的字段声明自己的serialVersionUID,该字段必须是静态的,最终的,并且类型为long

 ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
 
If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes. Android implementation of serialVersionUID computation will change slightly for some classes if you're targeting android N. In order to preserve compatibility, this change is only enabled is the application target SDK version is set to 24 or higher. It is highly recommended to use an explicit serialVersionUID field to avoid compatibility issues.

Implement Serializable Judiciously

Refer to Effective Java's chapter on serialization for thorough coverage of the serialization API. The book explains how to use this interface without harming your application's maintainability.

Recommended Alternatives

JSON is concise, human-readable and efficient. Android includes both a streaming API and a tree API to read and write JSON. Use a binding library like GSON to read and write Java objects directly.

也可以看看:

Hooray!