2011-08-18 21 views
27

HashMap实现Serializable接口;所以它可以被序列化。我看了HashMap的实现,Entry []表被标记为transient。由于Entry []表是存储Map的全部内容的表,如果它不能被序列化,在解序列化时如何构造回地图HashMap Serializability

回答

32

如果你看看the source,你会看到它没有依赖于默认序列化机制,但手动写出所有条目(如键和值的交替流):

/** 
    * Save the state of the <tt>HashMap</tt> instance to a stream (i.e., 
    * serialize it) 
    * 
    * @serialData The <i>capacity</i> of the HashMap (the length of the 
    *    bucket array) is emitted (int), followed by the 
    *    <i>size</i> (an int, the number of key-value 
    *    mappings), followed by the key (Object) and value (Object) 
    *    for each key-value mapping. The key-value mappings are 
    *    emitted in no particular order. 
    */ 
     private void writeObject(java.io.ObjectOutputStream s) 
      throws IOException 
     { 
      Iterator<Map.Entry<K,V>> i = 
       (size > 0) ? entrySet0().iterator() : null; 

      // Write out the threshold, loadfactor, and any hidden stuff 
      s.defaultWriteObject(); 

      // Write out number of buckets 
      s.writeInt(table.length); 

      // Write out size (number of Mappings) 
      s.writeInt(size); 

      // Write out keys and values (alternating) 
      if (i != null) { 
       while (i.hasNext()) { 
        Map.Entry<K,V> e = i.next(); 
        s.writeObject(e.getKey()); 
        s.writeObject(e.getValue()); 
       } 
      } 
     } 

这比阵列,它可以包含许多空条目和链接链和更紧凑的Map $ Entry包装的开销。

请注意,它仍然为“简单”字段调用defaultWriteObject。为了达到这个目的,它必须标记为transient

+0

我觉得有趣的是HashMap的加载因子没有被序列化。所以这些信息正在迷失。 –

+1

@PeterWippermann:你确定吗?这个'loadFactor'不是瞬态的,它应该包含在'defaultWriteObject'产生的输出中。 (实际上,直接调用defaultWriteObject之前的源代码中的注释直接提到了这一点)。 – Thilo

+1

哦,你当然是对的!我没有注意到它会受到默认序列化的影响。感谢您指点我! :-) –

8

HashMap负责通过使用writeObjectreadObject方法自己的序列化。

4

HashMaps在序列化过程中不序列化它们的Entry对象。看看它的writeObject方法。

的Javadoc解释:

HashMap中(桶阵列的长度)的容量是 发射(INT),随后的尺寸(一个int,的键值 映射数),然后为每个键值映射关键字(对象)和值(对象)。键值映射不是以特定的 顺序发出的。

如果您查看readObject方法,您将看到如何使用大小,键和值重建Entry表。