public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>
, Cloneable
, Serializable
{}
类定义:
HashMap继承了AbstractMap,实现Map,Cloneable,Serializable 接口
AbstractMap: 实现了一些方法,这里不做解释;
Cloneable:是一个标识接口,(应该是表示实现它的类允许被复制之类的。。。。)
构造方法:
/**
initialCapacity : MAP的初始容量
loadFactor :加载因子/系数
*/
public HashMap(int initialCapacity, float loadFactor) {
//初始容量不能设置为小于0
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
// MAXIMUM_CAPACITY是最大容量,默认是1 << 30 = 1073741824
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
//加载因子必须大于0
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
//获取下一次达到需要调整扩容的大小(容量*加载因子)
this.threshold = tableSizeFor(initialCapacity);
}
/**
设置初始容量
使用默认加载因子初始化Map,默认为0.75
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
使用默认容量和加载因子初始化Map
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
/**
将Map作为模板参数直接导入本HashMap
*/
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
类成员:
//默认的初始容量大小 16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//HashMap的最大容量 1073741824
static final int MAXIMUM_CAPACITY = 1 << 30;
//默认加载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//使用红黑树替代链表的阈值,>= 这个阈值链表将转化为红黑树
static final int TREEIFY_THRESHOLD = 8;
//当同一个桶上链表节点<= 6时,红黑树将转化为链表,反转
static final int UNTREEIFY_THRESHOLD = 6;
//HashMap可以将链表转化为树结构的最小阈值,也就是要达到64个桶位,才会开启转化
static final int MIN_TREEIFY_CAPACITY = 64;
//存储键值对数据
transient Set<Map.Entry<K,V>> entrySet;
//本HashMap中键值对数量
transient int size;
//此HashMap中结构变化的次数,改动次数
transient int modCount;
//如果初始化没有给HashMap分配桶容量大小,则这里保存的是默认大小DEFAULT_INITIAL_CAPACITY值
int threshold;
//这个存储的也是加载因子,而DEFAULT_LOAD_FACTOR 是没有指定情况下默认的加载因子
final float loadFactor;
下面看下HashMap的数据结构
transient Node<K,V>[] table;
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
.................
}
可以看出,HashMap基本结构是由数组+链表形式,如上图 array [1] 所示
数组中每个元素都是Node<K,V>类型,也就是键值对形式
static class Node<K,V> implements Map.Entry<K,V> {
final int hash; //哈希值
final K key; //key值
V value; //Value值
Node<K,V> next; //下一个节点对象的引用/指针
}
也就是说,Node<K,V>数组每个元素都可以容纳一条链表,该元素就是它容纳的链表的头节点,通过访问它的next属性,就可以遍历该链表所有元素。
主要看下节点类的3个方法
/**
获取该节点的Hash值
key的hash 和 value的hash 用按位异或运算
*/
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
/**
给该节点设置新值,返回原来的值
*/
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
/**
比较node节点对象内容是否相同
*/
public final boolean equals(Object o) {
//如果对象引用指向同一个对象,则相同
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
将key和value值进行比较,2者相同则相同
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}