为啥 ArrayList 使用瞬态存储?
Posted
技术标签:
【中文标题】为啥 ArrayList 使用瞬态存储?【英文标题】:Why does ArrayList use transient storage?为什么 ArrayList 使用瞬态存储? 【发布时间】:2012-04-08 12:57:46 【问题描述】:我在阅读 Java 的 ArrayList 的源代码时发现了它的支持数组声明:
private transient Object[] elementData;
为什么这需要是暂时的?为什么这个类不能序列化?
感谢您的帮助!
【问题讨论】:
【参考方案1】:为什么这需要是暂时的?
它这样做是因为它提供了自定义的readObject
和writeObject
方法,这些方法在序列化方面比默认方法做得更好。具体来说,writeObject 方法只写入元素的大小和序列。这避免了序列化私有数组对象,该对象 1) 具有自己的标头和开销,以及 2) 通常用 null
s 填充。节省空间非常重要。
为什么这个类不能序列化?
ArrayList
类作为一个整体可以序列化1。 Object[]
可以直接序列化,但他们选择将其标记为transient
以另一种方式实现序列化。
1 - 实际上,这取决于元素的运行时类型。例如,如果您尝试序列化包含 Thread
引用的 ArrayList
,那么您将获得第一个非空引用的运行时异常。
【讨论】:
只是想确认一下——“该字段根本不需要声明为transient”,因为在这种情况下提供了自定义的readObject
和writeObject
?
那一边是不正确的,我已将其删除。实际上,readObject/writeObject 使用 defaultReadObject/writeObject 方法来处理一些字段。因此,其他的需要标记为transient
。【参考方案2】:
因为它实现了显式序列化。请参阅 ArrayList#writeObject。
【讨论】:
【参考方案3】:ArrayList
实现了Serializable
,所以它可以被序列化,这就是为什么私有后备数组是transient
,所以它不会与类中的其他数据一起序列化,因为全部由ArrayList
的writeObject
和readObject
方法处理。
【讨论】:
【参考方案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
的字段有助于提高可读性,但由于自定义readObject
和writeObject
方法调用java.io.ObjectInputStream
的defaultReadObject
和java.io.ObjectOutputStream
的@987654329 @ 方法。这些方法将完成处理所有未标记为transient
(例如size
)的字段的序列化的繁琐工作。
在此处查看ObjectOutputStream
的源代码以获取更多详细信息:https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/io/ObjectOutputStream.java#L431
【讨论】:
是的……我自己也注意到了。更正了我的答案。谢谢。以上是关于为啥 ArrayList 使用瞬态存储?的主要内容,如果未能解决你的问题,请参考以下文章