在1.8中HashMap=数组+链表+红黑树 (由于使用了树形结构,增删改查的时间复杂度都为O(logN))
jdk1.8之前使用的是数组+链表结构,时间复杂度为O(N)
先确定数组长度(16)与起始位置
得到一个0-15的正整数
key.hashCode&16(维护node所在位置)(与运算,同为1为1,其余为0,用0补全)
Hash = key.hashCode^(异或)key.hashCode>>16
链表转红黑树的参数TREEIFY_THRESHOLD = 8(根据泊松分布)
红黑树转链表的参数UNTREEIFY_THRESHOLD = 6(为什么不为7?用来缓冲)
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
//序列号,序列化的时候使用。
private static final long serialVersionUID = 362498820763181265L;
/**默认容量,1向左移位4个,00000001变成00010000,也就是2的4次方为16,使用移位是因为移位是计算机基础运算,效率比加减乘除快。**/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//最大容量,2的30次方。
static final int MAXIMUM_CAPACITY = 1 << 30;
//加载因子,用于扩容使用。
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//当某个桶节点数量大于8时,会转换为红黑树。
static final int TREEIFY_THRESHOLD = 8;
//当某个桶节点数量小于6时,会转换为链表,前提是它当前是红黑树结构。
static final int UNTREEIFY_THRESHOLD = 6;
//当整个hashMap中元素数量大于64时,也会进行转为红黑树结构。
static final int MIN_TREEIFY_CAPACITY = 64;
//存储元素的数组,transient关键字表示该属性不能被序列化
transient Node<K,V>[] table;
//将数据转换成set的另一种存储形式,这个变量主要用于迭代功能。
transient Set<Map.Entry<K,V>> entrySet;
//元素数量
transient int size;
//统计该map修改的次数
transient int modCount;
//临界值,也就是元素数量达到临界值时,会进行扩容。
int threshold;
//也是加载因子,只不过这个是变量。
final float loadFactor;
}
关于Map和HashMap
1、Map是一个接口,HashMap继承AbstractMap接口和实现了Map接口的类;
2、Map是存储键和值这样的双列数据集合(类),但存储的数据是没有顺序的,其键不能重复,但其值是可以重复的,可以通过每一个键找到每一个对应的值;HashMap线程不同步的,即线程不安全的,但只有一个线程访问时效率较高;