37

我正在阅读 Java 的 ArrayList 的源代码,我遇到了它的支持数组声明:

private transient Object[] elementData;

为什么这需要是暂时的?为什么这个类不能序列化?

谢谢您的帮助!

4

6 回答 6

39

可以序列化;该类ArrayList只是自己处理事情,而不是使用默认机制。查看该类中的writeObject()和方法,它们是标准序列化机制的一部分。readObject()

如果您查看源代码,您会发现它writeObject()不会保存支持数组。相反,它一次一个地序列化元素(包括空值),直到达到size()限制。这避免了序列化数组的开销,尤其是数组末尾的任何未使用的插槽。在反序列化时,由readObject().

于 2012-03-24T00:50:00.833 回答
8

为什么这需要是暂时的?

它这样做是因为它提供了比默认值更好的序列化工作的自定义readObject和方法。writeObject具体来说,writeObject 方法只写入元素的大小和序列。这避免了序列化私有数组对象,该对象 1) 具有自己的标头和开销,以及 2) 通常用nulls 填充。节省空间可能是显着的。

为什么这个类不能序列化?

ArrayList作为一个整体可以序列化1Object[]可以直接序列化,但他们选择将其标记为以transient另一种方式实现序列化。


1 - 实际上,这取决于元素的运行时类型。例如,如果您尝试序列化ArrayList包含Thread引用,那么您将获得第一个非空引用的运行时异常。

于 2012-03-24T00:47:29.680 回答
5

ArrayListimplements Serializable,所以它可以被序列化,这就是为什么私有后备数组是transient,所以它不会与类中的其他数据一起序列化,因为所有都由ArrayList'swriteObjectreadObject方法处理。

于 2012-03-24T00:47:52.970 回答
2

因为它实现了显式序列化。请参阅 ArrayList#writeObject。

于 2012-03-24T00:47:33.800 回答
1

扩展上面斯蒂芬 C 的回答,我想更正他关于使用瞬态的注释,在ArrayLists这种情况下,为了可读性。作为他回答下的评论,这可能会更好,但我还没有那种能力!

虽然标记为的字段有助于提高可读性,但由于自定义和方法分别调用's和's方法transient,这也是必要的。这些方法将完成处理所有未标记字段(例如)的序列化的繁琐工作。readObjectwriteObjectjava.io.ObjectInputStreamdefaultReadObjectjava.io.ObjectOutputStreamdefaultWriteObjecttransientsize

ObjectOutputStream有关更多详细信息,请参阅源代码: https ://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/io/ObjectOutputStream.java#L431

于 2019-04-02T23:56:40.963 回答
0

该变量不可序列化。

  • 如果变量不可序列化,则序列化机制在尝试序列化变量时会抛出异常。为避免这种情况,您可以将变量声明为瞬态。

变量是多余的。

  • 假设实例缓存了计算的结果。在本地,我们可能希望存储计算结果,以节省一些处理器时间。但是当我们通过网络发送对象时,我们可能会更担心消耗带宽并因此丢弃缓存的计算,因为我们以后总是可以重新生成它。

链接:http ://onjava.com/pub/a/onjava/excerpt/JavaRMI_10/index.html?page=3

于 2012-03-24T00:56:40.737 回答