HashTable、HashMap与HashSet

1 table与map区别

我们先看2个类的定义

[java]  view plain copy
  1. public class Hashtable  
  2.     extends Dictionary  
  3.     implements Map, Cloneable, java.io.Serializable  
[java]  view plain copy
  1. public class HashMap  
  2.     extends AbstractMap  
  3.     implements Map, Cloneable, Serializable  

可见Hashtable 继承自 Dictiionary 而 HashMap继承自AbstractMap

Hashtable的put方法如下

[java]  view plain copy
  1. public synchronized V put(K key, V value) {  //###### 注意这里1  
  2.   // Make sure the value is not null  
  3.   if (value == null) { //###### 注意这里 2  
  4.     throw new NullPointerException();  
  5.   }  
  6.   // Makes sure the key is not already in the hashtable.  
  7.   Entry tab[] = table;  
  8.   int hash = key.hashCode(); //###### 注意这里 3  
  9.   int index = (hash & 0x7FFFFFFF) % tab.length;  
  10.   for (Entry e = tab[index]; e != null; e = e.next) {  
  11.     if ((e.hash == hash) && e.key.equals(key)) {  
  12.       V old = e.value;  
  13.       e.value = value;  
  14.       return old;  
  15.     }  
  16.   }  
  17.   modCount++;  
  18.   if (count >= threshold) {  
  19.     // Rehash the table if the threshold is exceeded  
  20.     rehash();  
  21.     tab = table;  
  22.     index = (hash & 0x7FFFFFFF) % tab.length;  
  23.   }  
  24.   // Creates the new entry.  
  25.   Entry e = tab[index];  
  26.   tab[index] = new Entry(hash, key, value, e);  
  27.   count++;  
  28.   return null;  
  29. }  
注意1 方法是同步的
注意2 方法不允许value==null
注意3 方法调用了key的hashCode方法,如果key==null,会抛出空指针异常 HashMap的put方法如下
[java]  view plain copy
  1. public V put(K key, V value) { //###### 注意这里 1  
  2.   if (key == null)  //###### 注意这里 2  
  3.     return putForNullKey(value);  
  4.   int hash = hash(key.hashCode());  
  5.   int i = indexFor(hash, table.length);  
  6.   for (Entry e = table[i]; e != null; e = e.next) {  
  7.     Object k;  
  8.     if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
  9.       V oldValue = e.value;  
  10.       e.value = value;  
  11.       e.recordAccess(this);  
  12.       return oldValue;  
  13.     }  
  14.   }  
  15.   modCount++;  
  16.   addEntry(hash, key, value, i);  //###### 注意这里   
  17.   return null;  
  18. }  

注意1 方法是非同步的
注意2 方法允许key==null
注意3 方法并没有对value进行任何调用,所以允许为null

补充: 
Hashtable 有一个 contains方法,容易引起误会,所以在HashMap里面已经去掉了
当然,2个类都用containsKey和containsValue方法。

结论: hashMap 在大多数情况下是优先选择的,运行速度快,但在多线程环境下要进行同步。


2 HashSet

对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSet 的源代码,可以看到如下代码: 
  1. public class HashSet<E>   
  2.  extends AbstractSet<E>   
  3.  implements Set<E>, Cloneable, java.io.Serializable   
  4. {   
  5.  // 使用 HashMap 的 key 保存 HashSet 中所有元素  
  6.  private transient HashMap<E,Object> map;   
  7.  // 定义一个虚拟的 Object 对象作为 HashMap 的 value   
  8.  private static final Object PRESENT = new Object();   
  9.  ...   
  10.  // 初始化 HashSet,底层会初始化一个 HashMap   
  11.  public HashSet()   
  12.  {   
  13.      map = new HashMap<E,Object>();   
  14.  }   
  15.  // 以指定的 initialCapacity、loadFactor 创建 HashSet   
  16.  // 其实就是以相应的参数创建 HashMap   
  17.  public HashSet(int initialCapacity, float loadFactor)   
  18.  {   
  19.      map = new HashMap<E,Object>(initialCapacity, loadFactor);   
  20.  }   
  21.  public HashSet(int initialCapacity)   
  22.  {   
  23.      map = new HashMap<E,Object>(initialCapacity);   
  24.  }   
  25.  HashSet(int initialCapacity, float loadFactor, boolean dummy)   
  26.  {   
  27.      map = new LinkedHashMap<E,Object>(initialCapacity   
  28.          , loadFactor);   
  29.  }   
  30.  // 调用 map 的 keySet 来返回所有的 key   
  31.  public Iterator<E> iterator()   
  32.  {   
  33.      return map.keySet().iterator();   
  34.  }   
  35.  // 调用 HashMap 的 size() 方法返回 Entry 的数量,就得到该 Set 里元素的个数  
  36.  public int size()   
  37.  {   
  38.      return map.size();   
  39.  }   
  40.  // 调用 HashMap 的 isEmpty() 判断该 HashSet 是否为空,  
  41.  // 当 HashMap 为空时,对应的 HashSet 也为空  
  42.  public boolean isEmpty()   
  43.  {   
  44.      return map.isEmpty();   
  45.  }   
  46.  // 调用 HashMap 的 containsKey 判断是否包含指定 key   
  47.  //HashSet 的所有元素就是通过 HashMap 的 key 来保存的  
  48.  public boolean contains(Object o)   
  49.  {   
  50.      return map.containsKey(o);   
  51.  }   
  52.  // 将指定元素放入 HashSet 中,也就是将该元素作为 key 放入 HashMap   
  53.  public boolean add(E e)   
  54.  {   
  55.      return map.put(e, PRESENT) == null;   
  56.  }   
  57.  // 调用 HashMap 的 remove 方法删除指定 Entry,也就删除了 HashSet 中对应的元素  
  58.  public boolean remove(Object o)   
  59.  {   
  60.      return map.remove(o)==PRESENT;   
  61.  }   
  62.  // 调用 Map 的 clear 方法清空所有 Entry,也就清空了 HashSet 中所有元素  
  63.  public void clear()   
  64.  {   
  65.      map.clear();   
  66.  }   
  67.  ...   
  68. }   

由上面源程序可以看出,HashSet 的实现其实非常简单,它只是封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。 
HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的,因此 HashSet 和 HashMap 两个集合在实现本质上是相同的。 

转自:http://blog.csdn.net/java2000_net/article/details/2512510
            http://alex09.iteye.com/blog/539549
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值