一 特性

  • key和value都不能为null,这个是不同于hashMap的,后者允许有一个键值对为null
  • HashTable容器使用synchronized来保证读写的线程安全
  • 内部初始数组容量是11,每次扩容为原来容量*2+1,负载则是8

    二 属性

    ```java

    // Hashtable是采用拉链法实现的,每一个Entry本质上是一个单向链表 private transient Entry[] table;

    // Hashtable中元素的实际数量 private transient int count;

    // 阈值,用于判断是否需要调整Hashtable的容量(threshold = 容量*加载因子) private int threshold;

    // 加载因子 private float loadFactor;

    // Hashtable被改变的次数 private transient int modCount = 0;

  1. <a name="IEdJt"></a>
  2. # 三 重要方法
  3. - rehash
  4. - 扩容方法
  5. <a name="DPu93"></a>
  6. # 四 构造方法
  7. ```java
  8. //使用给定的容量初始化,这里
  9. public Hashtable(int initialCapacity, float loadFactor) {
  10. if (initialCapacity < 0)
  11. throw new IllegalArgumentException("Illegal Capacity: "+
  12. initialCapacity);
  13. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  14. throw new IllegalArgumentException("Illegal Load: "+loadFactor);
  15. if (initialCapacity==0)
  16. initialCapacity = 1;
  17. this.loadFactor = loadFactor;
  18. table = new Entry<?,?>[initialCapacity];
  19. threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
  20. }
  21. public Hashtable(int initialCapacity) {
  22. this(initialCapacity, 0.75f);
  23. }
  24. //初始容量是11
  25. public Hashtable() {
  26. this(11, 0.75f);
  27. }
  28. public Hashtable(Map<? extends K, ? extends V> t) {
  29. this(Math.max(2*t.size(), 11), 0.75f);
  30. putAll(t);
  31. }

五 添加元素

  1. //使用synchronized关键字保证线程安全
  2. public synchronized V put(K key, V value) {
  3. // Make sure the value is not null
  4. if (value == null) {
  5. throw new NullPointerException();
  6. }
  7. // Makes sure the key is not already in the hashtable.
  8. Entry<?,?> tab[] = table;
  9. int hash = key.hashCode();
  10. int index = (hash & 0x7FFFFFFF) % tab.length;
  11. @SuppressWarnings("unchecked")
  12. Entry<K,V> entry = (Entry<K,V>)tab[index];
  13. //发生hash冲突 链表解决,
  14. for(; entry != null ; entry = entry.next) {
  15. //重复插入返回之前的值
  16. if ((entry.hash == hash) && entry.key.equals(key)) {
  17. V old = entry.value;
  18. entry.value = value;
  19. return old;
  20. }
  21. }
  22. addEntry(hash, key, value, index);
  23. return null;
  24. }
  25. private void addEntry(int hash, K key, V value, int index) {
  26. modCount++;
  27. Entry<?,?> tab[] = table;
  28. if (count >= threshold) {
  29. // Rehash the table if the threshold is exceeded
  30. rehash();
  31. tab = table;
  32. hash = key.hashCode();
  33. index = (hash & 0x7FFFFFFF) % tab.length;
  34. }
  35. // Creates the new entry.
  36. @SuppressWarnings("unchecked")
  37. Entry<K,V> e = (Entry<K,V>) tab[index];
  38. //这里构造函数采用头插法插入链表
  39. tab[index] = new Entry<>(hash, key, value, e);
  40. count++;
  41. }

六 删除元素

  1. public synchronized V remove(Object key) {
  2. Entry<?,?> tab[] = table;
  3. int hash = key.hashCode();
  4. int index = (hash & 0x7FFFFFFF) % tab.length;
  5. @SuppressWarnings("unchecked")
  6. Entry<K,V> e = (Entry<K,V>)tab[index];
  7. //找到对应的位置 并进行链表删除操作
  8. for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
  9. if ((e.hash == hash) && e.key.equals(key)) {
  10. modCount++;
  11. if (prev != null) {
  12. prev.next = e.next;
  13. } else {
  14. tab[index] = e.next;
  15. }
  16. count--;
  17. V oldValue = e.value;
  18. e.value = null;
  19. return oldValue;
  20. }
  21. }
  22. return null;
  23. }

七 获取元素

  1. //也是线程安全的方法
  2. public synchronized V get(Object key) {
  3. Entry<?,?> tab[] = table;
  4. int hash = key.hashCode();
  5. int index = (hash & 0x7FFFFFFF) % tab.length;
  6. for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
  7. if ((e.hash == hash) && e.key.equals(key)) {
  8. return (V)e.value;
  9. }
  10. }
  11. return null;
  12. }

八 扩容方法

  1. @SuppressWarnings("unchecked")
  2. protected void rehash() {
  3. int oldCapacity = table.length;
  4. Entry<?,?>[] oldMap = table;
  5. // overflow-conscious code
  6. //这里扩容大小为原始容量的两倍+1
  7. int newCapacity = (oldCapacity << 1) + 1;
  8. if (newCapacity - MAX_ARRAY_SIZE > 0) {
  9. if (oldCapacity == MAX_ARRAY_SIZE)
  10. // Keep running with MAX_ARRAY_SIZE buckets
  11. return;
  12. newCapacity = MAX_ARRAY_SIZE;
  13. }
  14. Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
  15. modCount++;
  16. //重新赋值伐值
  17. threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
  18. table = newMap;
  19. for (int i = oldCapacity ; i-- > 0 ;) {
  20. for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
  21. Entry<K,V> e = old;
  22. old = old.next;
  23. //重新计算位置
  24. int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  25. e.next = (Entry<K,V>)newMap[index];
  26. newMap[index] = e;
  27. }
  28. }
  29. }