0.出现时间?

  HashMap是jdk1.2

  Hashtable是jdk1.1

  HashMap出现得晚

1.线程安全?

HashMap线程不安全  Collections.synchronizedMap(map);

Hashtable线程安全  synchronized

2.null key?

  HashMap允许 null key。但是,null key只能有一个,null value可以有多个

  Hashtable不允许null key 和 null value,空指针异常

  由于HashMap允许null值,因此,当get(key)返回null时,两种情况:

    该key对应的value为null

    map中不存在该key

  因此,判断一个map中是否含有key时,应使用containsKey(key)

3.父类

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable

public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable

继承的父类不同,实现的接口相同

Dictionary是一个已经废弃的类

4.初始容量、加载因子

  HashMap:

    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

    static final int MAXIMUM_CAPACITY = 1 << 30;

    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    扩容:resize(2 * table.length);

    HashMap的长度总是2的n次方。

    如果在创建HashMap对象时,指定了初始大小,并且该大小不是2的n次方时,会自动调整为比指定值大的最接近的2的n次方;如果指定的初始大小大于MAXIMUM_CAPACITY ,则初始为MAXIMUM_CAPACITY 

public HashMap() {
  this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}

  Hashtable:

    初始:11

    加载因子:0.75F

    int newCapacity = (oldCapacity << 1) + 1;

    HashTable的总长度会尽量使用素数、奇数。

    如果在创建Hashtable对象时,手动指定了初始化大小,就直接使用给定的值

public Hashtable() {
  this(11, 0.75f);
}

 

5.hashCode计算

  当哈希表的长度为素数(Hashtable)时,取模的结果更均匀,冲突少

  当哈希表的长度为2的幂可以使用位运算得到结果,位运算效率高,由于使用2的幂长度的哈希表,冲突增加,所以,HashMap在得到key的hashcode之后,有做了一些处理,使冲突减少

  HashMap

int hash = hash(key);// 在得到对象的hash值之后,通过一系列的位运算打散数据,减少hash冲突
int i = indexFor(hash, table.length);  return h & (length-1);// 使用位运算得到键值对存储的位置

  Hashtable

int hash = hash(key);// 计算key的哈希值,就是对象的hash值
int index = (hash & 0x7FFFFFFF) % tab.length;// 哈希表的长度是素数或者奇数,直接取余就是该键值对在哈希表中存储的位置

6.底层实现

1.7都是数组+链表

private transient Entry<K,V>[] table;

HashMap 和 Hashtable 底层都是Entry<K,V>(内部类)

HashMap:static class Entry<K,V> implements Map.Entry<K,V>

Hashtable:private static class Entry<K,V> implements Map.Entry<K,V>

 

7.遍历方式

Iterator

Hashtable还使用了Enumeration

HashMap的Iterator是fail-fast迭代器

JDK8之前,Hashtable是没有fast-fail机制的。JDK8 ,HashTable也是使用fast-fail的

当有其它线程改变了HashMap的结构(增加,删除,修改元素),将会抛出ConcurrentModificationException。不过,通过Iterator的remove()方法移除元素则不会抛出ConcurrentModificationException异常。

8.API

  Hashtable比HashMap多两个public 方法

  elements()这个方法来自于抽象类Dictionary,该类已经废弃。

  contains()  containsValue()方法内部调用了该方法,实现的是同样的功能  

public boolean containsValue(Object value) {
  return contains(value);
}