序列化之间的区别是什么,只是将对象存储在磁盘上?

时间:2012-07-25 15:33:55

标签: java serialization serializable fileoutputstream objectoutputstream

我对此感到困惑。 从执行Serializable类开始,我们需要使用像FileOutputStreamObjectOutputStream这样的类。那么为什么我们不只是使用这些类来做一些事情,比如将对象输出到文件并从文件中输入对象以直接维护对象的状态?我们为什么要首先实现Serializable然后做同样的事情呢?

4 个答案:

答案 0 :(得分:3)

像这样理解......

Serializable是标记接口,表示您的类的对象可以转换为字节流,并在需要时最终返回到java对象。最初,您可能会认为每个类都应该是可序列化的,但这是不正确的考虑

输入和输出流,它们有一些文件句柄可供读取。当流变得不可用时,该文件句柄被关闭。因此,在这个实例中的序列化没有意义;并且反序列化永远不会恢复该句柄。

所以这应该回答为什么需要标记为Serializable?

现在实现定义如何写入或读取对象的方法;应该由您定义,因此您需要所有这些流对象和readObject,writeObject方法。希望这能让你对这个概念有更多的了解。

答案 1 :(得分:1)

Serializable只是一个标记接口,这意味着它只是用于向代码发出信号,该代码将实际执行您(程序员)知道(或希望:-))的序列化,这个类可以是序列化没有问题。

序列化本身就是将对象转换为可以存储或传输的东西 - 也就是说,作为字节流。您可以将序列化与freezedrying(用于制作雀巢咖啡的技术)进行比较 - 除去所有的水,只将咖啡精华存储在罐子中 - 只有对象的状态(字段值)才会转换为字节流,而不是其方法。

答案 2 :(得分:1)

正如fvu已经说过的,序列化是将类的实例转换为字节数组的过程,反之亦然。并非Java中的每个类都可以转换为字节数组(想想Thread类,将线程转换为字节数组没有意义)这就是你(和我们)的原因需要在 CAN 转换的对象中实现Serializable

Serializable只是一个标记接口,它不需要任何方法来实现。在大多数情况下,这已经足够了:只需使可序列化对象实现接口,然后使用默认行为。

默认序列化行为在ObjectInputStreamObjectOutputStream类中实现。 FileInputStreamFileOutputStream是不同的类,用于从磁盘上的文件读取和写入数据。

如果要将对象写入磁盘,则需要使用以下内容:

MyObject obj = ... // your object instance
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("/path/to/file"));
stream.writeObject(obj);

要回读对象,您需要这样:

ObjectInputStream stream = new ObjectInputStream(new FileInputStream("/path/to/file"));
MyObject obj = (MyObject) stream.readObject();

但有时你会想要将对象实例序列化/反序列化为内存而不是磁盘,然后你会使用这样的东西:

MyObject obj = ... // your object instance
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
byte[] data = baos.toByteArray();

我将省略从字节数组中读取对象的部分,因为它非常简单,但可以考虑使用JVM提供的所有不同输入/输出流的大量组合。


上面的示例使用默认的序列化行为。但是,您可能会遇到要序列化的给定类包含对未实现Serializable接口的其他类实例的引用的情况,那么我们如何序列化它们呢?我们需要使用transient修饰符标记这些引用,因此默认的序列化行为将忽略它们,我们需要覆盖默认行为,提供将在尝试时调用的私有readObjectwriteObject方法序列化/反序列化您的对象实例。

此外,某些类可能在序列化时提供替换对象(不同可序列化类的对象实例)。该替换对象将包含原始类的状态,其中原始类可以从该替换对象恢复。实现此行为是在原始类中提供writeReplace方法,在替换类中提供readReplace。请注意,原始类和替换类都必须实现Serializable接口,但只有替换对象中的数据才会被序列化

最后但并非最不重要的是,可以选择完全覆盖实现Externalizable接口的默认序列化协议。这不是Serializable的标记接口,您必须实现将对象的状态转换为数组的方法,反之亦然。您仍然会使用ObjectInputStream / ObjectOutputStream对来序列化( externalise ??)可外部化的对象实例,但现在是转换您的逻辑class到字节数组不再是JVM提供的那个,而是你在实现Externalizable类时在类中编写的那个。

所有这些信息都在thinksteep作为评论提供的link中。

答案 3 :(得分:0)

序列化是获取对象并将其写入字节数组(稍后从字节数组读取到对象)的过程

ObjectOutputStream在内部使用序列化,它使用serialize将对象转换为byte []并将其写入其输出