Map集合及HashMap源码分析
2017-05-18 16:24
549 查看
Map主要学习HashMap,TreeMap,HashTable
HashMap
因为HashMap是基于hash表实现的,所以不会hash数据结构的可以参考如下链接,hashMap是采用的链地址法来解决冲突
点击打开链接
以下面一段代码来分析hashMap源码
public void Test(){ HashMap<String,String> hashMap = new HashMap<String, String>(); hashMap.put("1", "m"); hashMap.put("2", "a"); hashMap.put("3", "p"); System.out.println(hashMap.get("1")); }
构造函数:
public HashMap(int initialCapacity, float loadFactor) { //检测参数,loadFactor表示装载因子,因为HashMap采用的链地址法,所以装载因子可以是1, // 但是会影响性能,默认选择为0.75 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; //该map中装载的最大数量 threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); //创建数组 table = new Entry[capacity]; useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); init(); }
put(K key, V value)
首先查找map中有没该元素,如果有,则直接替换其值,如果没有找到,则通过addEntry(int hash, K key, V value, int bucketIndex)插入数据,把这个值插入到链表的头部
public V put(K key, V value) { if (key == null)//插入key为null的值 return putForNullKey(value); int hash = hash(key);//获得hash值 int i = indexFor(hash, table.length);//获得在table中的索引 //迭代查找该元素在链表中要插入的位置 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //如果该map中已经有该key存在,那么替换其值即可 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; //如果没有此值,则已经找到位置,插入元素 addEntry(hash, key, value, i); return null; }
get(Object key)
public V get(Object key) { if (key == null) return getForNullKey(); //通过getEntry来查找 Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue(); }
final Entry<K,V> getEntry(Object key) { int hash = (key == null) ? 0 : hash(key);//得到hash值 //遍历此节点位置的链表 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; }
remove(Object key)
public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); }
final Entry<K,V> removeEntryForKey(Object key) { //获取hash值 int hash = (key == null) ? 0 : hash(key); //得到其索引 int i = indexFor(hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> e = prev; //遍历整个链表 while (e != null) { Entry<K,V> next = e.next; Object k; //找到要删除的值 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e)//表名删除的是链表的头 table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; }
与HashMap相对应的还有HashTable,HashMap和HashTable有什么区别
看一下HashTable源码:
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
可以看到,HashTable和HashMap一样,都是实现Map来实现的
来看put方法:
/**
* Maps the specified <code>key</code> to the specified
* <code>value</code> in this hashtable. Neither the key nor the
* value can be <code>null</code>. <p>
*
* The value can be retrieved by calling the <code>get</code> method
* with a key that is equal to the original key.
*
* @param key the hashtable key
* @param value the value
* @return the previous value of the specified key in this hashtable,
* or <code>null</code> if it did not have one
* @exception NullPointerException if the key or value is
* <code>null</code>
* @see Object#equals(Object)
* @see #get(Object)
*/
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 = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry<K,V> e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
return null;
}
从上面可以看到,增加了synchronized关键字,所以是线程安全的,还有注释说到,其key和value不能为空
所以HashMap和HashTable的区别如下:
1.HashTable是线程安全的,HashMap不是线程安全的
2.HashMap可以存储key和value为null的值,HashTable不能
3.还有一个区别HashMap的Iterator是fail-fast机制的,所以HashMap在迭代过程中,如果有集合有被修改,那么将会抛出ConcurrentModificationException异常,
而Hashtable的enumerator迭代器不是fail-fast.
TreeMap
TreeMap使用红黑树来实现,是一种有序的数据结构,因为总是处于一种平衡的状态,所以没有调优因子。
TreeMap和HashMap的区别
HashMap是hash表来实现,TreeMap使用红黑树来实现
TreeMap是有序的,HashMap是无序的
怎么选择使用HashMap还是TreeMap了
如果插入和更新都比较频繁的话,那么保证元素的有序可以提高快速和频繁查找的性能。如果对于排序操作(例如产生一个报表合作者运行一个批处理程序)的要求不是很频繁的话,那么把数据以无序的方式存储,然后在需要排序的时候用Collections.sort(…)来进行排序,会比用有序的方式来存储可能会更加高效
相关文章推荐
- 常用集合ArrayList,LinkedList,HashMap,HashSet源码分析
- Java集合系列之HashMap源码分析
- 【JAVA集合】HashMap源码分析(转载)
- Java 集合框架源码分析(三)——HashMap
- JUC源码分析14-集合-HashMap
- Java集合之HashMap源码实现分析
- JUC源码分析16-集合-ConcurrentSkipListMap、ConcurrentSkipListSet
- 【集合框架】JDK1.8源码分析之HashMap & LinkedHashMap迭代器(三)
- 【JAVA集合】HashMap源码分析
- 从源码分析java集合【HashMap】
- Map之HashMap源码分析
- 集合框架源码分析三(实现类篇ArrayList,LinkedList,HashMap)
- Java集合(8)--HashMap源码分析
- JAVA集合源码之路-Map分析(一)
- Java集合之HashMap源码分析
- Java集合框架之Map---HashMap源码分析
- Map之HashMap源码分析
- Java 集合框架源码分析(三)——HashMap
- 常用集合ArrayList,LinkedList,HashMap,HashSet源码分析
- Java集合:HashMap使用详解及源码分析