HashMap
哈希表(线程不安全,没有锁,会导致并发问题—扩容问题)
数组的时间复杂度O(n)
哈希冲突 哈希函数
构造函数(可以使元素均匀的分布在卡槽里):
1.直接寻址法(f(key)= key)
2.除留余数法(f(p) = p%n)
哈希冲突的解决方法
1.链地址法
构造函数:f(p) = p%16
数组+单项链表
2.探测法:pos(n) = f(n)+p(n)
(1)线性探测法:
(2)随机探测法:尾随机p(n) = random()
HashMap 的实现是 数组+链表
HashMap基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与 HashMap 实例的“容量”及其大小成比例。
hashmap的继承关系:
定义hashmap类
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
基本成员变量
{
// 默认的初始容量是16,必须是2的幂。
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
// 最大容量(必须是2的幂且小于2的30次方,传入容量过大将被这个值替换)
static final int MAXIMUM_CAPACITY = 1 << 30;
// 默认加载因子 0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 空表
static final Entry<?,?>[] EMPTY_TABLE = {};
// 存储数据的Entry数组,长度是2的幂。
// HashMap是采用拉链法实现的,每一个Entry本质上是一个单向链表
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
//已使用容量的大小
transient int size;
//阈值,超出需扩容(threshold=容量*加载因子)
int threshold;
//加载因子
final float loadFactor;
// HashMap被改变的次数
transient int modCount;
//HashMap的默认阀值
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
构造函数
// 指定“容量大小”和“加载因子”的构造函数
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +initialCapacity);
// HashMap的最大容量只能是MAXIMUM_CAPACITY
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
threshold = initialCapacity;
init();
}
// 指定“容量大小”的构造函数
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
// 默认构造函数
public HashMap() {
this(DEFAULT_INITIAL_CAPACITY,DEFAULT_LOAD_FACTOR);
}
// 包含Map的构造函数
public HashMap(Map<? extends K, ? extends V> m) {
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
inflateTable(threshold);
// 将m中的全部元素逐个添加到HashMap中
putAllForCreate(m);
}
返回索引值
// h & (length-1)保证返回值的小于length
static int indexFor(int h, int length) {
return h & (length-1);
}
返回当前已用大小
public int size() {
return size;
}
判断是否为空
public boolean isEmpty() {
return size == 0;
}
获取key对应的value
public V get(Object key) {
if (key == null)
return getForNullKey();
//获取到Entry实体
Entry<K,V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}
//获取到键为null的所对应的value值
private V getForNullKey() {
if (size == 0) {
return null;
}
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
HashMap是否包含key
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
返回“键为key”的键值对
final Entry<K,V> getEntry(Object key) {
//HashMap中无元素返回null
if (size == 0) {
return null;
}
// HashMap将key为null的元素存储在table[0]位置,key不为null的则调用hash()计算哈希值
int hash = (key == null) ? 0 : hash(key);
// 在hash值对应的链表上查找键值等于key的元素,找到返回
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;
}
// 将键值对添加到HashMap中
public V put(K key, V value) {
//如果为空表,则需要初始化
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
//如果key为null则将该键值对添加到table[0]中
if (key == null)
return putForNullKey(value);
// 若key不为null,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中
int hash = hash(key);
//获得其应该存放在数组中的位置
int i = indexFor(hash, table.length);
//遍历此位置
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
// 若key对应的键值对已经存在,则用新的value取代旧的value,并返回旧的value
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
// 若key对应的键值对不存在,则将键值对添加到table中
modCount++;
addEntry(hash, key, value, i);
return null;
}
将key为null键值对添加到table[0]位置
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}
putForCreate()是内部方法,它被构造函数等调用,用来创建HashMap
它和put()不同,put()是对外提供的往HashMap中添加元素的方法
private void putForCreate(K key, V value) {
int hash = null == key ? 0 : hash(key);
int i = indexFor(hash, table.length);
// 若HashMap中存在键值等于key的元素,则替换该元素的value值
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
e.value = value;
return;
}
}
// 若HashMap中不存在键值等于key的元素,则将键值对添加到HashMap中
createEntry(hash, key, value, i);
}
将m中的全部元素都添加到HashMap中,该方法被内部的构造HashMap的方法所调用
private void putAllForCreate(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
putForCreate(e.getKey(), e.getValue());
}
重新调整HashMap的大小,newCapacity是调整后的单位
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
// 新建一个HashMap,将旧HashMap的全部元素添加到新HashMap中
Entry[] newTable = new Entry[newCapacity];
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
将HashMap中的全部元素都添加到newTable中
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
将m的全部元素都添加到HashMap中
public void putAll(Map<? extends K, ? extends V> m) {
int numKeysToBeAdded = m.size();
if (numKeysToBeAdded == 0)
return;
if (table == EMPTY_TABLE) {
inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));
}
//判断是否需要扩容,当大于阀值就需要扩容
if (numKeysToBeAdded > threshold) {
int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
if (targetCapacity > MAXIMUM_CAPACITY)
targetCapacity = MAXIMUM_CAPACITY;
int newCapacity = table.length;
while (newCapacity < targetCapacity)
newCapacity <<= 1;
if (newCapacity > table.length)
resize(newCapacity);
}
//直接循环put
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
删除键为key元素,并返回以前的值
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
}
清空HashMap,将所有的元素设为null
public void clear() {
modCount++;
Arrays.fill(table, null);
size = 0;
}
克隆一个HashMap,并返回Object对象
public Object clone() {
HashMap<K,V> result = null;
try {
result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) {
// assert false;
}
if (result.table != EMPTY_TABLE) {
result.inflateTable(Math.min(
(int) Math.min(
size * Math.min(1 / loadFactor, 4.0f),
// we have limits...
HashMap.MAXIMUM_CAPACITY),
table.length));
}
result.entrySet = null;
result.modCount = 0;
result.size = 0;
result.init();
result.putAllForCreate(this);
return result;
}