JAVA中HashMap和Hashtable区别

Posted 知我者,足以

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA中HashMap和Hashtable区别相关的知识,希望对你有一定的参考价值。

Hashtable和HashMap在Java面试中相当容易被问到,甚至成为了集合框架面试题中最常被考的问题,所以在参加任何Java面试之前,都不要忘了准备这一题。

 

我们先看2个类的定义

public class Hashtable  
    extends Dictionary  
    implements Map, Cloneable, <a href="http://lib.csdn.net/base/javase" class=‘replace_word‘ title="Java SE知识库" target=‘_blank‘ style=‘color:#df3434; font-weight:bold;‘>Java</a>.io.Serializable  
public class HashMap  
    extends AbstractMap  
    implements Map, Cloneable, Serializable  

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

Hashtable的put方法如下

public synchronized V put(K key, V value) {  //###### 注意这里1  
  // Make sure the value is not null  
  if (value == null) { //###### 注意这里 2  
    throw new NullPointerException();  
  }  
  // Makes sure the key is not already in the hashtable.  
  Entry tab[] = table;  
  int hash = key.hashCode(); //###### 注意这里 3  
  int index = (hash & 0x7FFFFFFF) % tab.length;  
  for (Entry e = tab[index]; e != null; e = e.next) {  
    if ((e.hash == hash) && e.key.equals(key)) {  
      V old = e.value;  
      e.value = value;  
      return old;  
    }  
  }  
  modCount++;  
  if (count >= threshold) {  
    // Rehash the table if the threshold is exceeded  
    rehash();  
    tab = table;  
    index = (hash & 0x7FFFFFFF) % tab.length;  
  }  
  // Creates the new entry.  
  Entry e = tab[index];  
  tab[index] = new Entry(hash, key, value, e);  
  count++;  
  return null;  
}  

注意1 方法是同步的
注意2 方法不允许value==null
注意3 方法调用了key的hashCode方法,如果key==null,会抛出空指针异常

 

HashMap的put方法如下

public V put(K key, V value) { //###### 注意这里 1  
  if (key == null)  //###### 注意这里 2  
    return putForNullKey(value);  
  int hash = hash(key.hashCode());  
  int i = indexFor(hash, table.length);  
  for (Entry e = table[i]; e != null; e = e.next) {  
    Object k;  
    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
      V oldValue = e.value;  
      e.value = value;  
      e.recordAccess(this);  
      return oldValue;  
    }  
  }  
  modCount++;  
  addEntry(hash, key, value, i);  //###### 注意这里   
  return null;  
}  

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

 

是否提供contains方法

 HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人引起误解。

Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。

我们看一下Hashtable的ContainsKey方法和ContainsValue的源码:

public boolean containsValue(Object value) {      
     return contains(value);      
 }  
// 判断Hashtable是否包含“值(value)”      
 public synchronized boolean contains(Object value) {      
     //注意,Hashtable中的value不能是null,      
     // 若是null的话,抛出异常!      
     if (value == null) {      
         throw new NullPointerException();      
     }      
    
     // 从后向前遍历table数组中的元素(Entry)      
     // 对于每个Entry(单向链表),逐个遍历,判断节点的值是否等于value      
     Entry tab[] = table;      
     for (int i = tab.length ; i-- > 0 ;) {      
         for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {      
             if (e.value.equals(value)) {      
                 return true;      
             }      
         }      
     }      
     return false;      
 }  
// 判断Hashtable是否包含key      
 public synchronized boolean containsKey(Object key) {      
     Entry tab[] = table;      
/计算hash值,直接用key的hashCode代替    
     int hash = key.hashCode();        
     // 计算在数组中的索引值     
     int index = (hash & 0x7FFFFFFF) % tab.length;      
     // 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素      
     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {      
         if ((e.hash == hash) && e.key.equals(key)) {      
             return true;      
         }      
     }      
     return false;      
 }  

下面我们看一下HashMap的ContainsKey方法和ContainsValue的源码:

// HashMap是否包含key      
    public boolean containsKey(Object key) {      
        return getEntry(key) != null;      
    }  
// 返回“键为key”的键值对      
    final Entry<K,V> getEntry(Object key) {      
        // 获取哈希值      
        // HashMap将“key为null”的元素存储在table[0]位置,“key不为null”的则调用hash()计算哈希值      
        int hash = (key == null) ? 0 : hash(key.hashCode());      
        // 在“该hash值对应的链表”上查找“键值等于key”的元素      
        for (Entry<K,V> e = table[indexFor(hash, table.length)];      
             e != null;      
             e = e.next) {      
            Object k;      
            if (e.hash == hash &&      
                ((k = e.key) == key || (key != null && key.equals(k))))      
                return e;      
        }      
        return null;      
    }  
// 是否包含“值为value”的元素      
    public boolean containsValue(Object value) {      
    // 若“value为null”,则调用containsNullValue()查找      
    if (value == null)      
            return containsNullValue();      
     
    // 若“value不为null”,则查找HashMap中是否有值为value的节点。      
    Entry[] tab = table;      
        for (int i = 0; i < tab.length ; i++)      
            for (Entry e = tab[i] ; e != null ; e = e.next)      
                if (value.equals(e.value))      
                    return true;      
    return false;      
    }  

通过上面源码的比较,我们可以得到如下不同地方:key和value是否允许null值。

其中key和value都是对象,并且不能包含重复key,但可以包含重复的value。通过上面的ContainsKey方法和ContainsValue的源码我们可以很明显的看出:

Hashtable中,key和value都不允许出现null值。但是如果在Hashtable中有类似put(null,null)的操作,编译同样可以通过,因为key和value都是Object类型,但运行时会抛出NullPointerException异常,这是JDK的规范规定的。

HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

1.HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。

 

HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口。

主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。

HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。

HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。 

Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。

最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步(Collections.synchronizedMap)。 

Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异





以上是关于JAVA中HashMap和Hashtable区别的主要内容,如果未能解决你的问题,请参考以下文章

java中HashMap和HashTable有啥共同点和区别

Java 中 Hashtable与HashMap的区别

Java中HashSet,HashMap和HashTable的区别(转)

JAVA中HashMap和Hashtable区别

Java集合HashMap和Hashtable的区别

java 的HashMap和HashTable的区别?