Java中HashMap关键字transient的疑惑
HashMap中有个对象 transient Entry[] table;这个是存储数据的地方,但是为什么要加上关键字transient呢
对于transient的解释
transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,也就是说没法持久化。
那么这种设计为什么用在HashMap中呢?有什么用意
Answers
首先你要明白,一个HashMap从功能上来说就是一个Map。所谓Map,就是存放Key/Value的数据结构,所以,任何一个Map类的数据结构,从逻辑上说只包含key和value,其它所有的东西都只是辅助而已。
所以HashMap自己实现了readObject和writeObject,在其中它保存了bucket size,entry count(这两个其实不是必需的,但有助于提高效率)和所有的key/value(这个才是必须的)。
PS. 如果我没记错,其实它还调用了defaultReadObject/defaultWriteObject读写了load factor、threshold之类的其它一些东东。
好问题. 原因当然如 @Windoze 所言, 有效率的考虑, 但还有更深的原因.
Effective Java 2nd, Item75, Joshua大神提到:
For example, consider the case of a hash table. The physical
representation is a sequence of hash buckets containing key-value
entries. The bucket that an entry resides in is a function of the hash
code of its key, which is not, in general, guaranteed to be the same
from JVM implementation to JVM implementation. In fact, it isn't even
guaranteed to be the same from run to run. Therefore, accepting the
default serialized form for a hash table would constitute a serious
bug . Serializing and deserializing the hash table could yield an
object whose invariants were seriously corrupt.
怎么理解? 看一下HashMap.get()/put()知道, 读写Map是根据Object.hashcode()来确定从哪个bucket读/写. 而Object.hashcode()是native方法, 不同的JVM里可能是不一样的.
打个比方说, 向HashMap存一个entry, key为 字符串"STRING", 在第一个java程序里, "STRING"的hashcode()为1, 存入第1号bucket; 在第二个java程序里, "STRING"的hashcode()有可能就是2, 存入第2号bucket. 如果用默认的串行化(Entry[] table不用transient), 那么这个HashMap从第一个java程序里通过串行化导入第二个java程序后, 其内存分布是一样的. 这就不对了. HashMap现在的readObject和writeObject是把内容 输出/输入, 把HashMap重新生成出来.