hashmap的扩容因子是0.75 缘由 参考:HashMap默认加载因子为何选择0.75?(阿里)html
1. HashMap概述java
HashMap是基于哈希表的Map接口的非同步实现。此实现提供全部可选的映射操做,并容许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。面试
2. HashMap的数据结构编程
在java编程语言中,最基本的结构就是两种,一个是数组,另一个是模拟指针(引用),全部的数据结构均可以用这两个基本结构来构造的,HashMap也不例外。HashMap其实是一个“链表散列”的数据结构,即数组和链表的结合体。这样的结构结合了链表在增删方面的高效和数组在寻址上的优点数组
hashmap结构:哈希表是由数组+链表组成的,数组的默认长度为16 ,注意 hashtable的数组的默认长度是11(能够自动变长。在构造HashMap的时候也能够指定一个长度),数组里每一个元素存储的是一个链表的头结点。而组成链表的结点其实就是hashmap内部定义的一个类:Entity。Entity包含三个元素:key,value和指向下一个Entity的next数据结构
3. HashMap的存取app
这些元素是按照什么样的规则存储到数组中呢。通常状况是经过hash(key)%(len-1)得到,也就是元素的key的哈希值对数组长度取模获得。好比上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。因此十二、2八、108以及140都存储在数组下标为12的位置。编程语言
HashMap的存储--put:ide
int hash = key.hashCode(); // 这个hashCode方法这里不详述,只要理解每一个key的hash是一个固定的int值 int index = hash %( Entry[].length-1); table[index] = value;//假定存储链表头结点的数组名为table
用table[index]表示经过hash值计算出来的、元素须要存储在数组中的位置。先判断该位置上有没有存有Entity,没有的话就建立一个Entity<k,v>对象,在该位置上插入,插入结束;若是有的话,经过链表的遍历方式去逐个遍历,经过equals方法将key和已有的key进行比较,看看有没有已经存在的key,有的话用新的value替换老的value;若是没有,则在table[index]插入该Entity,把原来在table[index]位置上的Entity赋值给新的 Entity的next,也即,新的Entity插入(put)的位置永远是在链表的最前面(百度面试),这样插入结束。 函数
打个比方, 第一个键值对A进来,经过计算其key的hash获得的index=0,记作:table[0] = A。一会后又进来一个键值对B,经过计算其index也等于0,如今怎么办?HashMap会这样作:B.next = A,table[0] = B,若是又进来C,index也等于0,那么C.next = B,table[0] = C;这样咱们发现index=0的地方其实存取了A,B,C三个键值对,他们经过next这个属性连接在一块儿。
注:null key老是存放在Entry[]数组的第一个元素。
扩展:
按照散列函数的定义,若是两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但若是两个对象不一样,则它们的hashCode不必定不一样。
若是两个不一样对象的hashcode相同,就称为冲突。冲突会致使操做哈希表的时间开销增大,因此尽可能定义好的hashCode()方法,能加快哈希表的操做。覆盖了equals方法以后必定要覆盖hashCode方法,缘由很简单,好比,String a = new String(“abc”);String b = new String(“abc”);若是不覆盖hashCode的话,那么a和b的hashCode就会不一样,把这两个类当作key存到HashMap中的话就 会出现问题,就会和key的惟一性相矛盾。
HashMap的读取--get:
先定位到数组元素,再遍历该元素处的链表
public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); //先定位到数组元素,再遍历该元素处的链表 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.equals(k))) return e.value;//显然,在寻找目标元素的时候,除了对比经过key计算出来的hash值,还会用双等或equals方法对key自己来进行比较,二者都为true时才会返回这个元素 } return null; }
遍历规则:以下:
import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; public class abc_test { public static void main(String[] args) { // TODO Auto-generated method stub Map<String,String> map=new HashMap<String,String>(); map.put("1", "value1"); map.put("2", "value2"); map.put("3", "value3"); map.put("4", "value4"); //第一种:普通使用,二次取值 System.out.println("\n经过Map.keySet遍历key和value:"); for(String key:map.keySet()) { System.out.println("Key: "+key+" Value: "+map.get(key)); } //第二种:推荐,尤为是容量大时 System.out.println("\n经过Map.entrySet遍历key和value"); for(Map.Entry<String, String> entry: map.entrySet()) { System.out.println("Key: "+ entry.getKey()+ " Value: "+entry.getValue()); } //第三种 System.out.println("\n经过Map.values()遍历全部的value,但不能遍历key"); for(String v:map.values()) { System.out.println("The value is "+v); } //第四种 System.out.println("\n经过Iterator 遍历Map.entrySet的key和value: "); Iterator map1it=map.entrySet().iterator(); while(map1it.hasNext()) { Map.Entry<String, String> entry=(Entry<String, String>) map1it.next(); System.out.println("Key: "+entry.getKey()+" Value: "+entry.getValue()); } //第五种 System.out.println("\n经过iterator 遍历Map.keySet的key和value: "); Iterator keyIter=map.keySet().iterator(); while(keyIter.hasNext()) { String key=(String)keyIter.next(); System.out.println("Key: "+key+" Value: "+map.get(key)); } } private static void print(Collection<Person> set) { Iterator<Person> it = set.iterator(); while (it.hasNext()) { Person p = it.next(); System.out.println(p.toString()); } } } class test { public int d; public String name; public int getD() { return d; } public void setD(int d) { this.d = d; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub return super.equals(obj); } } class Person { public Person(String name, int age) { this.name = name; this.age = age; } private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString() { return "{" + name + ", " + age + "}"; } } class joinDemo implements Runnable{ @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<10;i++){ System.out.println("线程1第"+i+"次执行"); } } }
结果为:
经过Map.keySet遍历key和value: Key: 1 Value: value1 Key: 2 Value: value2 Key: 3 Value: value3 Key: 4 Value: value4 经过Map.entrySet遍历key和value Key: 1 Value: value1 Key: 2 Value: value2 Key: 3 Value: value3 Key: 4 Value: value4 经过Map.values()遍历全部的value,但不能遍历key The value is value1 The value is value2 The value is value3 The value is value4 经过Iterator 遍历Map.entrySet的key和value: Key: 1 Value: value1 Key: 2 Value: value2 Key: 3 Value: value3 Key: 4 Value: value4 经过iterator 遍历Map.keySet的key和value: Key: 1 Value: value1 Key: 2 Value: value2 Key: 3 Value: value3 Key: 4 Value: value4