首页 > 编程语言 > 详细

java-map之Hashtable

时间:2020-08-09 11:06:41      阅读:80      评论:0      收藏:0      [点我收藏+]

1.1 概述

HashTable也是一个散列表,它存储的内容是键值对映射。HashTable继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。HashTable的函数都是同步的,这意味着它是线程安全的。它的Key、Value都不可以为null。此外,HashTable中的映射不是有序的。

1.2详解

//为一个Entry[]数组类型,Entry代表了“拉链”的节点,每一个Entry代表了一个键值对,哈希表的"key-value键值对"都是存储在Entry数组中的。
private transient Entry<?,?>[] table;

//HashTable的大小,注意这个大小并不是HashTable的容器大小,而是他所包含Entry键值对的数量。
private transient int count;

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

//加载因子。
private float loadFactor;

//用来实现“fail-fast”机制的(也就是快速失败)。所谓快速失败就是在并发集合中,其进行迭代操作时,若有其他线程对其进行结构性的修改,这时迭代器会立马感知到,并且立即抛出ConcurrentModificationException异常,而不是等到迭代完成之后才告诉你(你已经出错了)
private transient int modCount = 0;

  • put方法
    1.获取synchronized锁。
    2.put方法不允许null值,如果发现是null,则直接抛出异常。
    3.计算key的哈希值和index
    4.遍历对应位置的链表,如果发现已经存在相同的hash和key,则更新value,并返回旧值。
    5.如果不存在相同的key的Entry节点,则调用addEntry方法增加节点。
//获取synchronized锁
public synchronized V put(K key, V value) {
    // Make sure the value is not null
    //如果value是空抛出异常
    if (value == null) {
        throw new NullPointerException();
    }

    // Makes sure the key is not already in the hashtable.
    Entry<?,?> tab[] = table;
    //计算key的哈希值和index
    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;
}

  • get方法
    1.先获取synchronized锁。
    2.计算key的哈希值和index。
    3.在对应位置的链表中寻找具有相同hash和key的节点,返回节点的value。
    4.如果遍历结束都没有找到节点,则返回null。
public synchronized V get(Object key) {//根据键取出对应索引  
      Entry tab[] = table;  
      int hash = hash(key);//先根据key计算hash值  
      int index = (hash & 0x7FFFFFFF) % tab.length;//再根据hash值找到索引  
      for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {//遍历entry链  
          if ((e.hash == hash) && e.key.equals(key)) {//若找到该键  
              return e.value;//返回对应的值  
          }  
      }  
      return null;//否则返回null  
  }  

  • remove方法
    1.先获取synchronized锁。
    2.计算key的哈希值和index。
    3.遍历对应位置的链表,寻找待删除节点,如果存在,用e表示待删除节点,pre表示前驱节点。如果不存在,返回null。
    4.更新前驱节点的next,指向e的next。返回待删除节点的value值。
public synchronized V remove(Object key) {
    Entry<?,?> tab[] = table;
    //计算key的哈希值和index
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    @SuppressWarnings("unchecked")
    Entry<K,V> e = (Entry<K,V>)tab[index];
    for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
        //遍历对应位置的链表,寻找待删除节点
        if ((e.hash == hash) && e.key.equals(key)) {
            modCount++;
			//更新前驱节点的next,指向e的next
            if (prev != null) {
                prev.next = e.next;
            } else {
                tab[index] = e.next;
            }
            count--;
            V oldValue = e.value;
            e.value = null;
            //返回待删除节点的value值
            return oldValue;
        }
    }
    //如果不存在,返回null
    return null;
}

和hashmap的主要区别:

  • hashtable支持并发编程,是线程安全的。
    主要是因为其底层使用了synchronized关键字。但是这样牺牲了效率。当需要多线程操作的时候也可以使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
  • hashtable不支持key和value为空。当出翔put(null,null)的时候会出现空指针异常。
  • 扩容机制和hash值不同。
    Hashtable直接使用Object的hashCode(),hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值,然后再使用去取模运算来获得最终的位置。两者的默认负载因子都是0.75,但Hashtable扩容时,容量变为原来的2倍+1,HashMap扩容时,将容量变成原来的2倍;Hashtable在不制定容量的情况下默认容量是11,也就是说Hashtable会尽量使用素数、奇数,而HashMap 的默认容量 为16,Hashtable不要求底层数组的容量为2的整数次幂,而 HashMap 要求一定为2的整数次幂。

java-map之Hashtable

原文:https://www.cnblogs.com/jiezao/p/13461597.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!