HashMap的数据结构为 数组+单向链表。那么是如何添加数据以及扩容的时候数据如何重新散列的呢?我模仿者源码进行了简单的实现。
public class MyHashMap<K, V> {
private int size;
private static final int MINIMUM = 4;
private static final int MAXMUM = 1 << 30;
private int threshode;// 阈值
// 用来强制扩容
private static final Entry[] EMPTY_TABLE = new MyHashMapEntry[MINIMUM >> 1];
MyHashMapEntry<K, V> entryForNullKey;// 存放空的键
private MyHashMapEntry<K, V>[] table;// 核心
public MyHashMap() {
table = (MyHashMapEntry<K, V>[]) EMPTY_TABLE;
threshode = -1;
}
public MyHashMap(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("capacity:" + capacity);
}
if (capacity == 0) {
table = (MyHashMapEntry<K, V>[]) EMPTY_TABLE;
threshode = -1;
return;
}
if (capacity < MINIMUM) {
capacity = MINIMUM;
} else if (capacity > MAXMUM) {
capacity = MAXMUM;
} else {
capacity = roundUpToPowerOfTwo(capacity);
}
makeTable(capacity);
}
// put函数
public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}
int hash = secondHash(key.hashCode());
MyHashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);// 找到需要存在数组的下表
// 先检查是否存在相同的键
for (MyHashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
if ((hash == e.hashcode) && (key.equals(e.key))) {
V oldValue = e.getValue();
e.setValue(value);
return oldValue;
}
}
// 如果超过阈值 来时进行扩容
if (++size > threshode) {
tab = doubleCapaticy();
index = hash & (tab.length - 1);
}
addNewEntry(key, value, hash, index);
return null;
}
// 返回size
public int size() {
return size;
}
// 获取值
public V get(K key) {
if (key == null) {
MyHashMapEntry<K, V> entry = entryForNullKey;
return entry == null ? null : entry.value;
}
MyHashMapEntry<K, V>[] entries = table;
int hash = secondHash(key.hashCode());
int index = hash & (entries.length - 1);
for (MyHashMapEntry<K, V> n = entries[index]; n != null; n = n.next) {
K eKey = n.key;
if ((eKey == key) || ((n.hashcode == hash) && (key.equals(eKey)))) {
return n.value;
}
}
return null;
}
// 从链表头部插入
private void addNewEntry(K key, V value, int hash, int index) {
table[index] = new MyHashMapEntry<K, V>(key, value, hash, table[index]);
}
/**
* @Description: 双倍扩容方法
* @date 2017年9月23日 上午10:49:15
*/
private MyHashMapEntry<K, V>[] doubleCapaticy() {
MyHashMapEntry<K, V>[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXMUM) {
return oldTable;
}
int newCapaticy = oldCapacity << 1;
MyHashMapEntry<K, V>[] newTable = makeTable(newCapaticy);
if (size == 0) {
return newTable;
}
// 开始重新散列
for (int j = 0; j < oldCapacity; j++) {
MyHashMapEntry<K, V> e = oldTable[j];// 拿到每个羊肉串
if (e == null) {
continue;
}
int heighBit = e.hashcode & oldCapacity;
MyHashMapEntry<K, V> broken = null;
newTable[j | heighBit] = e;// 下标位置
for (MyHashMapEntry<K, V> n = e.next; n != null; e = n, n = n.next) {
int nextHeighBit = n.hashcode & oldCapacity;
if (nextHeighBit != heighBit) {
if (broken == null) {
int newNextIndex = j | nextHeighBit;// 新的索引
newTable[newNextIndex] = n;
} else {
broken.next = n;
}
broken = e;
heighBit = nextHeighBit;
}
}
if (broken != null) {
broken.next = null;
}
}
return newTable;
}
// 进行数组的散列 hashMap的hash算法
private int secondHash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
// 放空key的
private V putValueForNullKey(V value) {
MyHashMapEntry<K, V> entry = entryForNullKey;
if (entry == null) {
entry = new MyHashMapEntry<K, V>(null, value, 0, null);
size++;
return null;
} else {
V oldValue = entry.getValue();
entry.setValue(value);
return oldValue;
}
}
// 创建数组
private MyHashMapEntry[] makeTable(int capacity) {
// 创建局部变量以避免多线程访问该数组改变其长度时出现问题
MyHashMapEntry[] newTable = new MyHashMapEntry[capacity];
table = newTable;
threshode = (capacity >> 1) + (capacity >> 2);
return newTable;
}
// 转换成2的幂次方
public static int roundUpToPowerOfTwo(int i) {
i--;
i |= i >>> 1;
i |= i >>> 2;
i |= i >>> 4;
i |= i >>> 8;
i |= i >>> 16;
return i + 1;
}
// 初始化键值类
static class MyHashMapEntry<K, V> implements Entry<K, V> {
final K key;
V value;
final int hashcode;
MyHashMapEntry next;
public MyHashMapEntry(K key, V value, int hashCode, MyHashMapEntry next) {
this.key = key;
this.value = value;
this.hashcode = hashCode;
this.next = next;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
V oleValue = this.value;
this.value = value;
return oleValue;
}
@Override
public int hashCode() {
return (key == null ? 0 : key.hashCode())
^ (value == null ? 0 : value.hashCode());
}
}
}
测试:
public static void main(String[] args) {
MyHashMap<String, String> map = new MyHashMap<String, String>();
map.put("dasdsa", "1");
map.put("dasd12sa", "7");
map.put("dasd4sa", "6");
map.put("dasd542sa", "5");
map.put("das56dsa", "4");
map.put("dasd76sa", "3");
map.put("dasd98sa", "2");
map.put(null,"1");
System.out.println(map.size());
System.out.println("dasd98sa:"+map.get("dasd98sa"));
map.put("dasd98sa", "000");
System.out.println("dasd98sa:"+map.get("dasd98sa"));
System.out.println(map.size());
}
测试结果如下:
8
dasd98sa:2
dasd98sa:000
8