Java容器之HashMap源码总结
Map是一种将对象和对象相关联的设计;HashMap设计用来快速访问,TreeMap保持键始终处于排序状态,所以没有HashMap快。
Map的数据结构是链表的数据,根据hash值确定数组下标,hash值冲突时采用拉链法拓展哈希表。
map中key和value都可以为null
Map接口
package gemme.collection;
import java.util.Set;
/**
* 自定义接口Map
* */
public interface IMyMap<K, V> {
// 元素数目
int size();
// 集合是否为空
boolean isEmpty();
// 是否包含Key
boolean containsKey(Object key);
// 根据键获取值
V get(Object key);
// 将键值对放入集合中
V put(K key, V value);
// 移除键值对
V remove(Object key);
interface MyEntry<K, V> {
K getKey();
V getValue();
V setValue(V newValue);
boolean equals(Object o);
int hashCode();
}
}
抽象类和实现类
package gemme.collection;
/**
* 自定义抽象类AbstractMap
* */
public abstract class IMyAbstractMap<K, V> implements IMyMap<K, V> {
}
package gemme.collection;
import java.util.Objects;
public class MyHashMap<K, V> extends IMyAbstractMap<K, V> implements IMyMap<K, V> {
//默认初始化大小 16
int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//默认负载因子 0.75
float DEFAULT_LOAD_FACTOR = 0.75f;
//元素个数
int size;
// 临界值
int threshold;
// 负载因子
float loadFactor;
MyEntry<?, ?>[] EMPTY_TABLE = {};
// 哈希表
MyEntry<K, V>[] table = (MyEntry<K, V>[]) EMPTY_TABLE;
public MyHashMap() {
threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
loadFactor = DEFAULT_LOAD_FACTOR;
size = 0;
}
/**
* 获取key的哈希值
* */
int hash(Object k) {
int h = 0;
h ^= k.hashCode();
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
/**
* 当Key为空时,Entry下标为0,拿到该链表遍历并比较它们的Key
* */
private V getForNullKey() {
if (size == 0) {
return null;
}
for (MyEntry<K, V> e = table[0]; e != null; e = e.next) {
if (null == e.getKey()) {
return e.getValue();
}
}
return null;
}
/**
* 根据键值获取entry,先计算哈希值,根据哈希值找到ENTRY链表,遍历链表
* */
MyEntry<K, V> getEntry(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
for (MyEntry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
Object k = e.key;
if (e.hash == hash && (k == key || (k != null && k.equals(key) ))){
return e;
}
}
return null;
}
static int indexFor(int h, int length) {
return h & (length - 1);
}
@Override
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
/**
* 根据键获取值
* */
@Override
public V get(Object key) {
if (null == key) {
return getForNullKey();
}
MyEntry<K, V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}
@Override
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
// 初始化
threshold = (int) (DEFAULT_INITIAL_CAPACITY * loadFactor);
table = new MyEntry[DEFAULT_INITIAL_CAPACITY];
}
if (null == key) {
putForNullKey(value);
}
int hash = hash(key);
int index = indexFor(hash, table.length);
//遍历index位置的entry,若找到重复key则更新对应entry的值,然后返回
for (MyEntry<K, V> e = table[index]; e != null; e = e.next) {
if (e.hash == hash && (e.key == key || key.equals(e.key))) {
V oldValue = e.getValue();
e.setValue(value);
return oldValue;
}
}
addEntry(hash, key, value, index);
return null;
}
private void addEntry(int hash, K key, V value, int index) {
// 判断size是否达到临界值,若已达到则进行扩容,将table的capacicy翻倍
if (size > threshold) {
resize(2 * table.length);
hash = (key != null) ? hash(key) : 0;
index = indexFor(hash, table.length);
}
// 将新的entry放到table的index位置第一个,若原来有值则以链表形式存放
MyEntry<K, V> entry = table[index];
table[index] = new MyEntry<>(hash, key, value, entry);
size++;
}
private void resize(int newCapacity) {
MyEntry[] newTable = new MyEntry[newCapacity];
// 遍历原table,将每个entry都重新计算hash放入newTable中
for (MyEntry<K, V> e : table) {
while (null != e) {
MyEntry<K, V> next = e.next;
int i = indexFor(e.hash, newCapacity);
// 将entry指到新的newTable,设置next
e.next = newTable[i];
// 设置newTable的值为e
newTable[i] = e;
e = next;
}
}
// 用newTable替table
table = newTable;
// 修改临界值
threshold = (int) (table.length * DEFAULT_LOAD_FACTOR);
}
private V putForNullKey(V value) {
for (MyEntry<K, V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
addEntry(0, null, value, 0);
return null;
}
@Override
public V remove(Object key) {
MyEntry<K, V> e = removeEntryForKey(key);
return e == null ? null : e.getValue();
}
MyEntry<K, V> removeEntryForKey(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length);
MyEntry<K, V> prev = table[i];
MyEntry<K, V> e = prev;
while (e != null) {
MyEntry<K, V> next = e.next;
if (e.hash == hash && (e.key == key || key.equals(e.key))) {
size--;
// 如果删除的是链表的第一个节点
if (prev == e) {
table[i] = next;
} else {
// 不是链表的第一个节点,前一个节点直接指向next
prev.next = next;
}
return e;
}
prev = e;
e = next;
}
// 没有找到对应的节点,返回null
return null;
}
/**
* 自定义节点MyEntry
* */
static class MyEntry<K, V> implements IMyMap.MyEntry<K, V> {
K key;
V value;
MyEntry<K, V> next;
int hash;
MyEntry(int h, K k, V v, MyEntry<K, V> n) {
hash = h;
key = k;
value = v;
next = n;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
@Override
public boolean equals(Object o) {
return false;
}
public int hashCode() {
return Objects.hash(getKey()) ^ Objects.hash(getValue());
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (MyEntry entry : table) {
while (entry != null) {
sb.append(entry.getKey() + ":" + entry.getValue() + " ");
entry = entry.next;
}
}
return sb.toString();
}
}