为啥 ArrayList 使用瞬态存储?

Posted

技术标签:

【中文标题】为啥 ArrayList 使用瞬态存储?【英文标题】:Why does ArrayList use transient storage?为什么 ArrayList 使用瞬态存储? 【发布时间】:2012-04-08 12:57:46 【问题描述】:

我在阅读 Java 的 ArrayList 的源代码时发现了它的支持数组声明:

private transient Object[] elementData;

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

感谢您的帮助!

【问题讨论】:

【参考方案1】:

为什么这需要是暂时的?

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

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

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


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

【讨论】:

只是想确认一下——“该字段根本不需要声明为transient”,因为在这种情况下提供了自定义的readObjectwriteObject 那一边是不正确的,我已将其删除。实际上,readObject/writeObject 使用 defaultReadObject/writeObject 方法来处理一些字段。因此,其他的需要标记为transient【参考方案2】:

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

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

如果查看源代码,您会看到 writeObject() 没有保存支持数组。相反,它一次将一个元素(包括空值)序列化到size() 限制。这避免了序列化数组的开销,尤其是数组末尾的任何未使用的插槽。在反序列化时,readObject() 创建了一个具有最小所需大小的新后备数组。

【讨论】:

【参考方案5】:

该变量不可序列化。

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

变量是多余的。

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

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

【讨论】:

这些并不能解释为什么在这种情况下elementData 被标记为transient。 1) Object[] 元素将是可序列化的,否则ArrayList 的序列化将失败。 2) ArrayList 的元素不是“冗余的”。有关正确解释,请参阅其他答案。【参考方案6】:

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

虽然标记为transient 的字段有助于提高可读性,但由于自定义readObjectwriteObject 方法调用java.io.ObjectInputStreamdefaultReadObjectjava.io.ObjectOutputStream 的@987654329 @ 方法。这些方法将完成处理所有未标记为transient(例如size)的字段的序列化的繁琐工作。

在此处查看ObjectOutputStream 的源代码以获取更多详细信息:https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/io/ObjectOutputStream.java#L431

【讨论】:

是的……我自己也注意到了。更正了我的答案。谢谢。

以上是关于为啥 ArrayList 使用瞬态存储?的主要内容,如果未能解决你的问题,请参考以下文章

为啥杰克逊还要序列化瞬态成员?

Java - 为啥瞬态成员变量在 Java 标准库中使用如此广泛?

ArrayList存储字符串并遍历

为啥没有窥视! clojure 瞬态向量的函数?

为啥Java有瞬态字段?

为啥 ArrayLists 的 ArrayList 不是多维的?