HashMap和HashTable的区别

   Hashtable 与 HashMap 的简单比较

  1. HashTable 基于 Dictionary 类,而 HashMap 是基于 AbstractMap。Dictionary 是任何可将键映射到相应值的类的抽象父类,而 AbstractMap 是基于 Map 接口的实现,它以最大限度地减少实现此接口所需的工作。
  2. HashMap 的 key 和 value 都允许为 null,而 Hashtable 的 key 和 value 都不允许为 null。HashMap 遇到 key 为 null 的时候,调用 putForNullKey 方法进行处理,而对 value 没有处理;Hashtable遇到 null,直接返回 NullPointerException。
  3. Hashtable 方法是同步,而HashMap则不是。我们可以看一下源码,Hashtable 中的几乎所有的 public 的方法都是 synchronized 的,而有些方法也是在内部通过 synchronized 代码块来实现。所以有人一般都建议如果是涉及到多线程同步时采用 HashTable,没有涉及就采用 HashMap,但是在 Collections 类中存在一个静态方法:synchronizedMap(),该方法创建了一个线程安全的 Map 对象,并把它作为一个封装的对象来返回。

       HashMap源码:

       HashMap key为null时,通过单独的hash()方法来判断,若为null,则值为0;

       value为null时,源码分析,没有进行对value的判断。

  1 public class HashMap<K,V> extends AbstractMap<K,V>
  2     implements Map<K,V>, Cloneable, Serializable {
  3    
4 static final int hash(Object key) { 5 int h; 6 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 7 } 8 9 10 /** 11 * Constructs an empty <tt>HashMap</tt> with the specified initial 12 * capacity and load factor. 13 * 14 * @param initialCapacity the initial capacity 15 * @param loadFactor the load factor 16 * @throws IllegalArgumentException if the initial capacity is negative 17 * or the load factor is nonpositive 18 */ 19 public HashMap(int initialCapacity, float loadFactor) { 20 if (initialCapacity < 0) 21 throw new IllegalArgumentException("Illegal initial capacity: " + 22 initialCapacity); 23 if (initialCapacity > MAXIMUM_CAPACITY) 24 initialCapacity = MAXIMUM_CAPACITY; 25 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 26 throw new IllegalArgumentException("Illegal load factor: " + 27 loadFactor); 28 this.loadFactor = loadFactor; 29 this.threshold = tableSizeFor(initialCapacity); 30 } 31 32 /** 33 * Constructs an empty <tt>HashMap</tt> with the specified initial 34 * capacity and the default load factor (0.75). 35 * 36 * @param initialCapacity the initial capacity. 37 * @throws IllegalArgumentException if the initial capacity is negative. 38 */ 39 public HashMap(int initialCapacity) { 40 this(initialCapacity, DEFAULT_LOAD_FACTOR); 41 } 42 43 /** 44 * Constructs an empty <tt>HashMap</tt> with the default initial capacity 45 * (16) and the default load factor (0.75). 46 */ 47 public HashMap() { 48 this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted 49 } 50 51 /** 52 * Constructs a new <tt>HashMap</tt> with the same mappings as the 53 * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with 54 * default load factor (0.75) and an initial capacity sufficient to 55 * hold the mappings in the specified <tt>Map</tt>. 56 * 57 * @param m the map whose mappings are to be placed in this map 58 * @throws NullPointerException if the specified map is null 59 */ 60 public HashMap(Map<? extends K, ? extends V> m) { 61 this.loadFactor = DEFAULT_LOAD_FACTOR; 62 putMapEntries(m, false); 63 } 64 65  public V put(K key, V value) { 66 return putVal(hash(key), key, value, false, true); 67 } 68 69 /** 70 * Implements Map.put and related methods 71 * 72 * @param hash hash for key 73 * @param key the key 74 * @param value the value to put 75 * @param onlyIfAbsent if true, don't change existing value 76 * @param evict if false, the table is in creation mode. 77 * @return previous value, or null if none 78 */ 79 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, 80 boolean evict) { 81 Node<K,V>[] tab; Node<K,V> p; int n, i; 82 if ((tab = table) == null || (n = tab.length) == 0) 83 n = (tab = resize()).length; 84 if ((p = tab[i = (n - 1) & hash]) == null) 85 tab[i] = newNode(hash, key, value, null); 86 else { 87 Node<K,V> e; K k; 88 if (p.hash == hash && 89 ((k = p.key) == key || (key != null && key.equals(k)))) 90 e = p; 91 else if (p instanceof TreeNode) 92 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); 93 else { 94 for (int binCount = 0; ; ++binCount) { 95 if ((e = p.next) == null) { 96 p.next = newNode(hash, key, value, null); 97 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 98 treeifyBin(tab, hash); 99 break; 100 } 101 if (e.hash == hash && 102 ((k = e.key) == key || (key != null && key.equals(k)))) 103 break; 104 p = e; 105 } 106 } 107 if (e != null) { // existing mapping for key 108 V oldValue = e.value; 109 if (!onlyIfAbsent || oldValue == null) 110 e.value = value; 111 afterNodeAccess(e); 112 return oldValue; 113 } 114 } 115 ++modCount; 116 if (++size > threshold) 117 resize(); 118 afterNodeInsertion(evict); 119 return null; 120 } 121 122 /** 123 * Initializes or doubles table size. If null, allocates in 124 * accord with initial capacity target held in field threshold. 125 * Otherwise, because we are using power-of-two expansion, the 126 * elements from each bin must either stay at same index, or move 127 * with a power of two offset in the new table. 128 * 129 * @return the table 130 */ 131 final Node<K,V>[] resize() { 132 Node<K,V>[] oldTab = table; 133 int oldCap = (oldTab == null) ? 0 : oldTab.length; 134 int oldThr = threshold; 135 int newCap, newThr = 0; 136 if (oldCap > 0) { 137 if (oldCap >= MAXIMUM_CAPACITY) { 138 threshold = Integer.MAX_VALUE; 139 return oldTab; 140 } 141 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && 142 oldCap >= DEFAULT_INITIAL_CAPACITY) 143 newThr = oldThr << 1; // double threshold 144 } 145 else if (oldThr > 0) // initial capacity was placed in threshold 146 newCap = oldThr; 147 else { // zero initial threshold signifies using defaults 148 newCap = DEFAULT_INITIAL_CAPACITY; 149 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); 150 } 151 if (newThr == 0) { 152 float ft = (float)newCap * loadFactor; 153 newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? 154 (int)ft : Integer.MAX_VALUE); 155 } 156 threshold = newThr; 157 @SuppressWarnings({"rawtypes","unchecked"}) 158 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; 159 table = newTab; 160 if (oldTab != null) { 161 for (int j = 0; j < oldCap; ++j) { 162 Node<K,V> e; 163 if ((e = oldTab[j]) != null) { 164 oldTab[j] = null; 165 if (e.next == null) 166 newTab[e.hash & (newCap - 1)] = e; 167 else if (e instanceof TreeNode) 168 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); 169 else { // preserve order 170 Node<K,V> loHead = null, loTail = null; 171 Node<K,V> hiHead = null, hiTail = null; 172 Node<K,V> next; 173 do { 174 next = e.next; 175 if ((e.hash & oldCap) == 0) { 176 if (loTail == null) 177 loHead = e; 178 else 179 loTail.next = e; 180 loTail = e; 181 } 182 else { 183 if (hiTail == null) 184 hiHead = e; 185 else 186 hiTail.next = e; 187 hiTail = e; 188 } 189 } while ((e = next) != null); 190 if (loTail != null) { 191 loTail.next = null; 192 newTab[j] = loHead; 193 } 194 if (hiTail != null) { 195 hiTail.next = null; 196 newTab[j + oldCap] = hiHead; 197 } 198 } 199 } 200 } 201 } 202 return newTab; 203 } 204 205 }

   HashTable源码:

    HashTable , key会在方法中使用key.hashCode();若为null直接抛出异常

    value为null时,会在方法中判断。

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

       public Hashtable(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);

        if (initialCapacity==0)
            initialCapacity = 1;
        this.loadFactor = loadFactor;
        table = new Entry<?,?>[initialCapacity];
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    }

    /**
     * Constructs a new, empty hashtable with the specified initial capacity
     * and default load factor (0.75).
     *
     * @param     initialCapacity   the initial capacity of the hashtable.
     * @exception IllegalArgumentException if the initial capacity is less
     *              than zero.
     */
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }

    /**
     * Constructs a new, empty hashtable with a default initial capacity (11)
     * and load factor (0.75).
     */
    public Hashtable() {
        this(11, 0.75f);
    }    
        public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }

        addEntry(hash, key, value, index);
        return null;
    }

 private void addEntry(int hash, K key, V value, int index) {
        modCount++;

        Entry<?,?> tab[] = table;
        if (count >= threshold) {
            // Rehash the table if the threshold is exceeded
            rehash();

            tab = table;
            hash = key.hashCode();
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        // Creates the new entry.
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>) tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }
       @SuppressWarnings("unchecked")
    protected void rehash() {
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;

        // overflow-conscious code
        int newCapacity = (oldCapacity << 1) + 1;
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            if (oldCapacity == MAX_ARRAY_SIZE)
                // Keep running with MAX_ARRAY_SIZE buckets
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
        Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

        modCount++;
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        table = newMap;

        for (int i = oldCapacity ; i-- > 0 ;) {
            for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                old = old.next;

                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }
    }
}

 

posted @ 2018-04-13 13:44  ♩一叶之秋♪  阅读(164)  评论(0编辑  收藏  举报