手写HashMap
- JDK1.7 的HashMap 是基于,数组和单向链表实现。大致原理是:当put的元素的时候,根据key的值和数组的大小,获取该元素在数组中存入的位置,如果当前位置是空,直接添加一个节点。反之,遍历链表进行添加或者修改。HashMap的扩容机制是,当容器内存储的元素个数大于,负载因子和数组的大小的乘积的时候,进行扩容,默认是2倍。并且需要重新,计算数组中的元素的位置。
package com.work.one.map;
/**
* Created by 廖开雷 on 2020/2/4.
*/
public interface MyMap<K, V> {
void put (K k, V v);
V get (K k);
V remove (K k);
int size ();
}
package com.work.one.map.impl;
import com.work.one.map.MyMap;
/**
*
* Created by 廖开雷 on 2020/2/4.
* hashMap 是基于 数组和单链表实现的
* 单链表只维护 当前节点的下一个元素
* 为什么用单链表,是因为其实根本用不到 双链表中pre
*/
@SuppressWarnings("all")
public class LklHashMap<K, V> implements MyMap<K, V> {
private int size = 0;
private Entry[] tables;
private float loadFactors = 0.75f;
public LklHashMap(int initCapacity) {
tables = new Entry[initCapacity];
}
@Override
public void put(K k, V v) {
//存储在数组中的位置
int index = k.hashCode() % tables.length;
// 直接放入吧
Entry newEntry = new Entry(k, v);
//判断目标位置是否存在元素,不存在则直接添加
if (tables[index] == null) {
tables[index] = newEntry;
size ++ ;
} else {
Entry start = tables[index];
//修改
if (start.getK().equals(k) || start.getK() == k) {
start.setV(v);
return;
}
boolean hasKey = false;
//修改
Entry now = start;
while (now != null) {
if (now.getK().equals(k)) {
now.setV(v);
hasKey = true;
break;
}
now = now.next;
}
if (hasKey) {
return;
}
System.out.println("hash crash,put the value in the first..");
newEntry.next = start;
tables[index] = newEntry;
size ++ ;
}
//如果 map中存储的元素个数大于 数组的 长度和负载因子的乘积 则扩容
if (size > tables.length * loadFactors) {
resize();
}
}
/**
*
* 扩容
*/
private void resize () {
System.out.println(" resize is begin....");
int newCapacity = tables.length * 2;
Entry<K, V>[] newTables = new Entry[newCapacity];
for (int i = 0; i < tables.length; i++) {
Entry<K, V> entry = tables[i];
while (entry != null) {
K k = entry.getK();
V v = entry.getV();
int newIndex = k.hashCode() % newTables.length;
Entry<K, V> newEntry = new Entry<>(k, v);
//放入新的数组的新位置
Entry oldEnrty = newTables[newIndex];
if (oldEnrty == null) {
newTables[newIndex] = newEntry;
size ++ ;
} else {
// 存在的话就修改
boolean hasKey = false;
while (oldEnrty.next != null) {
if (oldEnrty.getK().equals(k) || oldEnrty.getK() == k) {
oldEnrty.setV(v);
hasKey = true;
break;
}
oldEnrty = oldEnrty.next;
}
if (hasKey) {
continue;
}
//不存在的话就放入链表的头部
newEntry.next = oldEnrty;
newTables[newIndex] = newEntry;
size ++ ;
}
entry = entry.next;
}
}
tables = newTables;
System.out.println(" resize is end.... new capacity is : " + tables.length);
}
@Override
public V get(K k) {
int index = k.hashCode() % tables.length;
Entry target = tables[index];
if (target == null) {
return null;
}
if (target.getK().equals(k)) {
return (V)target.getV();
}
while (target.next != null) {
Entry temp = target.next;
if (temp.getK().equals(k)) {
return (V)temp.getV();
}
target = target.next;
}
return null;
}
public void print () {
for (int i = 0; i < tables.length ; i++) {
Entry entry = tables[i];
while (entry != null) {
System.out.println("hashCode : "+ entry.getK().hashCode() % tables.length + ",key:" + entry.getK() + ",value:" + entry.getV());
entry = entry.next;
}
}
}
@Override
public V remove(K k) {
return null;
}
@Override
public int size() {
return this.size;
}
class Entry<K, V> {
K k;
V v;
Entry next;
public Entry (K k, V v) {
this.k = k;
this.v = v;
}
public K getK() {
return k;
}
public void setK(K k) {
this.k = k;
}
public V getV() {
return v;
}
public V setV(V v) {
V old = this.v;
this.v = v;
return old;
}
}
}
测试:
package com.work.one.map.impl;
/**
* Created by 廖开雷 on 2020/2/4.
*/
public class TestMap {
public static void main(String[] args) {
LklHashMap<String, String> map = new LklHashMap<>(16);
map.put("1号", "aa1");
map.put("2号", "bb2");
map.put("3号", "cc3");
map.put("4号", "dd4");
map.put("5号", "dd5");
map.put("6号", "dd6");
map.put("7号", "dd7");
map.put("12号", "dd12");
//会发生hash碰撞
System.out.println("1号".hashCode() % 16);
System.out.println("12号".hashCode() % 16);
System.out.println(map.get("a"));
map.print();
}
}