Externalizable的替代方法
若不是特别在意要实现Externalizable接口,还有另一种方法可供选用。我们可以实现Serializable接口,并添加(注意是“添加”,而非“覆盖”或者“实现”)名为writeObject()和readObject()的方法。一旦对象被序列化或者重新装配,就会分别调用那两个方法。也就是说,只要提供了这两个方法,就会优先使用它们,而不考虑默认的序列化机制。
这些方法必须含有下列准确的签名:
private void
writeObject(ObjectOutputStream stream)
throws IOException;
private void
readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
从设计的角度出发,情况变得有些扑朔迷离。首先,大家可能认为这些方法不属于基础类或者Serializable接口的一部分,它们应该在自己的接口中得到定义。但请注意它们被定义成“private”,这意味着它们只能由这个类的其他成员调用。然而,我们实际并不从这个类的其他成员中调用它们,而是由ObjectOutputStream和ObjectInputStream的writeObject()及readObject()方法来调用我们对象的writeObject()和readObject()方法(注意我在这里用了很大的抑制力来避免使用相同的方法名——因为怕混淆)。大家可能奇怪ObjectOutputStream和ObjectInputStream如何有权访问我们的类的private方法——只能认为这是序列化机制玩的一个把戏。
在任何情况下,接口中的定义的任何东西都会自动具有public属性,所以假若writeObject()和readObject()必须为private,那么它们不能成为接口(interface)的一部分。但由于我们准确地加上了签名,所以最终的效果实际与实现一个接口是相同的。
看起来似乎我们调用ObjectOutputStream.writeObject()的时候,我们传递给它的Serializable对象似乎会被检查是否实现了自己的writeObject()。若答案是肯定的是,便会跳过常规的序列化过程,并调用writeObject()。readObject()也会遇到同样的情况。
还存在另一个问题。在我们的writeObject()内部,可以调用defaultWriteObject(),从而决定采取默认的writeObject()行动。类似地,在readObject()内部,可以调用defaultReadObject()。下面这个简单的例子演示了如何对一个Serializable对象的存储与恢复进行控制:
//: SerialCtl.java
// Controlling serialization by adding your own
// writeObject() and readObject() methods.
import java.io.*;
public class SerialCtl implements Serializable {
String a;
transient String b;
public SerialCtl(String aa, String bb) {
a = "Not Transient: " + aa;
b = "Transient: " + bb;
}
public String toString() {
return a + "\n" + b;
}
private void
writeObject(ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
stream.writeObject(b);
}
private void
readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
b = (String)stream.readObject();
}
public static void main(String[] args) {
SerialCtl sc =
new SerialCtl("Test1", "Test2");
System.out.println("Before:\n" + sc);
ByteArrayOutputStream buf =
new ByteArrayOutputStream();
try {
ObjectOutputStream o =
new ObjectOutputStream(buf);
o.writeObject(sc);
// Now get it back:
ObjectInputStream in =
new ObjectInputStream(
new ByteArrayInputStream(
buf.toByteArray()));
SerialCtl sc2 = (SerialCtl)in.readObject();
System.out.println("After:\n" + sc2);
} catch(Exception e) {
e.printStackTrace();
}
}
} ///:~
在这个例子中,一个String保持原始状态,其他设为transient(临时),以便证明非临时字段会被defaultWriteObject()方法自动保存,而transient字段必须在程序中明确保存和恢复。字段是在构建器内部初始化的,而不是在定义的时候,这证明了它们不会在重新装配的时候被某些自动化机制初始化。
若准备通过默认机制写入对象的非transient部分,那么必须调用defaultWriteObject(),令其作为writeObject()中的第一个操作;并调用defaultReadObject(),令其作为readObject()的第一个操作。这些都是不常见的调用方法。举个例子来说,当我们为一个ObjectOutputStream调用defaultWriteObject()的时候,而且没有为其传递参数,就需要采取这种操作,使其知道对象的句柄以及如何写入所有非transient的部分。这种做法非常不便。
transient对象的存储与恢复采用了我们更熟悉的代码。现在考虑一下会发生一些什么事情。在main()中会创建一个SerialCtl对象,随后会序列化到一个ObjectOutputStream里(注意这种情况下使用的是一个缓冲区,而非文件——与ObjectOutputStream完全一致)。正式的序列化操作是在下面这行代码里发生的:
o.writeObject(sc);
其中,writeObject()方法必须核查sc,判断它是否有自己的writeObject()方法(不是检查它的接口——它根本就没有,也不是检查类的类型,而是利用反射方法实际搜索方法)。若答案是肯定的,就使用那个方法。类似的情况也会在readObject()上发生。或许这是解决问题唯一实际的方法,但确实显得有些古怪。
分享到:
相关推荐
实现`Externalizable`的类需要覆盖`writeExternal()`和`readExternal()`方法,自行决定哪些字段需要序列化和如何序列化。这种方式通常用于需要优化序列化性能或者有特殊序列化需求的情况。 **四、serialVersionUID*...
在本教程中,我们将深入探讨DOM4J的主要功能和使用方法。 ### 1. DOM4J简介 DOM4J是基于DOM模型的,但它比Java内置的DOM API更易于使用,性能也更优。它支持SAX和DOM解析,并且提供了一个强大的事件驱动模型,使得...
对于更高级的控制,如自定义序列化行为,可以实现`java.io.Externalizable`接口,自行编写`writeExternal`和`readExternal`方法。 **RMI实例** 一个简单的RMI实例包括定义远程接口、实现远程接口的类、生成Stub和...
Externalizable 接口提供了 writeExternal 和 readExternal 两个方法,用于手动实现对象的序列化和反序列化。 在实际应用中,序列化机制可以应用于各种领域,如网络通信、数据存储、分布式计算等。例如,在网络通信...
Java中的序列化机制有两种实现方式: 一种是实现Serializable接口 ...2 仅仅提供两个空方法,实现该接口必须为两个空方法提供实现 3 性能略好 博客地址:http://blog.csdn.net/u010156024/article/details/44306879
- **`Externalizable`接口**:这是`Serializable`接口的一个子接口,它要求实现类提供两个方法`readExternal`和`writeExternal`来自定义序列化和反序列化的过程。 #### 二、序列化的具体实现方式 在Java中,对象...
* 使用 Externalizable 接口实现序列化和反序列化 * 使用 Java 序列化 API 实现序列化和反序列化 在实际开发中,选择合适的序列化和反序列化方法取决于具体的需求和场景。在本例中,我们使用 Serializable 接口实现...
这通常通过实现`Externalizable`接口并在其中重写`writeExternal()`和`readExternal()`方法来实现。这种方法提供了更高级别的控制,允许开发者决定哪些数据应该被序列化,以及如何序列化和反序列化数据。 #### 使用...
- **实现`Externalizable`接口**:如果`Customer`类实现了`Externalizable`接口,那么必须实现`readExternal`和`writeExternal`方法。此时,序列化过程将通过调用`writeExternal`方法进行,而反序列化时,则先通过无...
`Externalizable`接口就是一个例子,它规定了`writeExternal`和`readExternal`方法,任何实现`Externalizable`的类都必须提供这两个方法的实现。 对比抽象类和接口,我们可以总结以下几点: 1. **默认实现**:抽象...
- ConcurrentHashMap:线程安全的HashMap替代品,提供更高的并发性能。 【线程方法】 - sleep():使当前线程暂停指定时间,不会释放持有的锁。 - wait():使线程等待,释放锁,直到其他线程调用notify()或...
Serializable有一个子接口Externalizable,实现Externalizable接口的类可以自行控制对象序列化荷反序列化过程。 一般来说,没有必要自己实现序列化接口,直接交给Java虚拟机是上策。 实现了序列化接口的类,如果...
- 序列化机制通过 Externalizable 或 Serializable 接口实现。 11. 在 Java 中不可变对象(Immutable Objects): - 一旦被创建,状态不能改变。 - 优点是线程安全。 - 示例:String、Integer。 12. Java 中的...
1)Serializable和Externalizable接口Xstream框架2)Simple框架 3)Apache的AXIOM框架 2、XML验证文档的生成工具 trang.jar 3、利用XSD文件的XML3种验证方法 1)Dom4j的SAXValidator (dom4j.jar, javax.xml....
这种过程是通过 ObjectOutputStream 类的 writeObject 方法实现的,该方法将对象转换为字节序列,并将其写入到目标输出流中。 在 Socket 编程中,对象流可以用来传输复杂数据。例如,在客户端和服务器端之间传输...
- 使用`writeObject()`和`readObject()`方法替代`writeFields()`和`readFields()`,可以避免序列化整个对象,只序列化必要的字段。 - 对于大型或复杂对象,考虑使用` farkle.SerializationUtils`等第三方库进行更...
- 类实现`Externalizable`接口,必须实现`readExternal(ObjectInput)`和`writeExternal(ObjectOutput)`方法。 - 通过这些方法可以完全控制序列化过程,包括如何写入和读取对象的数据。 六、知识点五:版本兼容性...
如果类实现了`Externalizable`接口,那么必须手动实现`writeExternal()`和`readExternal()`方法,这两个方法负责控制对象的序列化和反序列化逻辑。这样,开发者可以精确地控制哪些字段被序列化,以及如何恢复这些...
- **解决方案**:使用`Arrays.toString(args)`和`Arrays.hashCode(args)`来替代。 ##### 15. "instanceof" operators that always return "true" or "false" should be removed - **解释**:某些情况下,`...