Hashtable和HashMap对象源码分析
来源:互联网 发布:鼠标指针主题 知乎 编辑:程序博客网 时间:2024/06/05 02:16
- Hashtable中put源码
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; }
根据K的hash值计算出key,value对应该放的位置,然后查找该entry链表上是否存在要插入的key,如果存在更新value值,同时返回oldValue。
如果不存在要插入的key则执行addEntry(……)操作。注意这里put操作存在关键字synchronized,所以put操作是同步的,线程安全,但是在多线程的环境下效率不高。
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++; }
根据当前容器中对象个数来判断是否需要进行rehash操作,即调整数组的容量,这里有初始化因子一些概念,想了解详细如何rehash操作,可以研究rehash()函数。
接着,new一个新的entry实现,并放在链表的头部。
- HashMap中put方法
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }/** * Implements Map.put and related methods * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
首先也是计算key的hash值,得到要放入桶中的位置,如果该位置没有元素直接加入 tab[i] = newNode(hash, key, value, null);
如果桶中指定位置第一个元素的hash值以及key相等的元素则把value值替换。
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; //替换value值 if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; }
第一个元素key不相等,则遍历整个链表,这时有两种结果
a.找到key相等的元素,替换value值,并返回oldvalue
b.没找到key相等的元素,new一个节点,加入到链表的尾部,返回null
for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; }
- HashSet
public boolean add(E e) { return map.put(e, PRESENT)==null;}private static final Object PRESENT = new Object();……private transient HashMap<E,Object> map;……public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
可以看出HashSet中实际上是包含了一个hashMap的,只是这里的value恒为Object,所以HashMap的特性都适用于HashSet.
**总结:
不同点:
1.Hashtable 线程安全,新插入元素插入的链表的头部。
2.HashMap 非线程安全,新插入元素插入链表尾部。
相同点:
都是采用数组加链表的存储结构,只不过HashMap采用的是节点,Hashtable采用的entry,实质是一样的。**
- Hashtable和HashMap对象源码分析
- Hashtable和HashMap对象
- HashTable和HashMap分析
- Hashtable和HashMap分析
- [源码解析]HashMap和HashTable的区别(源码分析解读)
- [源码解析]HashMap和HashTable的区别(源码分析解读)
- [源码解析]HashMap和HashTable的区别(源码分析解读)
- [源码解析]HashMap和HashTable的区别(源码分析解读)
- 源码分析——HashMap和HashTable区别
- 观察源码分析HashMap和Hashtable的区别
- 从源码的角度分析Hashtable和HashMap的区别
- 源码分析—HashMap、HashSet、HashTable
- HashMap和HashTable源码学习笔记
- 分析Vector、ArrayList和hashtable hashmap数据结构
- Hashtable和HashMap的差异化分析
- HashMap HashTable ConcurrentHashMap key和value是否可以null的问题 源码分析
- Java面试之从源码的角度分析Hashtable和HashMap
- HashMap HashTable ConcurrentHashMap key和value是否可以null的问题 源码分析
- Linux 2. 关于pthread_cond_signal 唤醒两个线程的问题
- MindManager报“xml字符非法”的解决办法
- 2017.06.02回顾 模型评价的正确方法
- td在relative模式下,IE9不显示border,chrome正常显示边框
- tcp/ip 相关知识点
- Hashtable和HashMap对象源码分析
- sublime/android studio复制整行到下一行
- Bluetooth之BluetoothAdapter
- datatable分页增加首页和尾页
- javascript中变量的类型转换
- eclipse启动时报错java was started but returned exit code=13
- docker使用
- 区块链简介
- 2017年第0届浙江工业大学之江学院程序设计竞赛决赛--A(二分法+容斥原理)