- 默认长度16,加载因子0.75,空间换时间
- JDK1.8时,当链表长度超过8,链表会转变为红黑树
- 扩容的性能是很低的,要选择合适的容量
HashMap存储结构图
为什么说HashMap线程不安全?
比如有两个线程需要同时进行rehash操作,当线程A执行到Entry<K, V> oldEntry=(Entry<K, V>) entry.getNext();时,线程B开始 rehash操作,且操作完成。此时线程A的引用已经是线程B rehash操作之后的引用。当线程A继续执行,将entry处理完之后,就需要处理oldEntry,但是此时oldentry的引用已经指向了entry,之后会不停的处理entry和oldentry,就造成了循环。
HashMap接口
public interface MyMap<K, V> {
//向集合中插入值
public V put(K k,V v);
//根据Key获取集合中的值
public V get(K k);
//获取集合元素个数
public int size();
//用于获取集合中键值对的对象
interface Entry<K,V>{
K getKey();
V getValue();
Entry<K,V> getNext();
Entry<K,V> setNext(Entry<K,V> next);
V setValue(V value);
}
}
HashMap的具体实现
public class MyHashMap<K, V> implements MyMap<K, V>{
//Entry类型的数组,默认16,用于存放Entry数据
private Entry<K, V> table[]=null;
//记录hashmap的元素个数
private int size;
//定义初始容量16
private static int defaultLength=16;
//定义加载因子0.75
private static double defaultLod=0.75;
public MyHashMap() {
table=new Entry[defaultLength];
}
@Override
public V put(K k, V v) {
if(size >= this.defaultLength * this.defaultLod){
//扩容
reHash();
}
int index=getIndex(k,defaultLength);
//判断是不是修改
MyMap.Entry<K, V> entry=table[index];
while(entry!=null){
if(entry.getKey().equals(k)){
//修改替换
return entry.setValue(v);
}else{
//循环判断下一个元素
entry=entry.getNext();
}
}
//创建元素并且存放在table的index上
table[index]=new Entry<>(k,v,table[index]);
size++;
return v;
}
//扩容,重新散列
private void reHash() {
if(size >= this.defaultLength * this.defaultLod){
System.out.println("扩容开始");
Entry<K, V> newTable[]=new Entry[this.defaultLength << 1];
Entry<K, V> entry=null;
for (int i = 0; i < table.length; i++) {
entry=table[i];
while(entry!=null){
//进行重新散列
int index=getIndex(entry.getKey(),newTable.length);
Entry<K, V> oldEntry=(Entry<K, V>) entry.getNext();
entry.setNext(newTable[index]);
newTable[index]=entry;
//指向下一个节点
entry = oldEntry;
}
}
table= newTable;
this.defaultLength = newTable.length;
newTable=null;
}
}
//哈希算法获取数组下标
private int getIndex(K k,int length) {
if(k==null)
return 0;
int hash=k.hashCode();
//与算法
return hash & (length-1);
}
@Override
public V get(K k) {
if(table!=null){
int index=getIndex(k,defaultLength);
MyMap.Entry<K, V> entry=table[index];
while(entry!=null){
if(entry.getKey().equals(k)){
return entry.getValue();
}else{
entry=entry.getNext();
}
}
}
return null;
}
@Override
public int size() {
return this.size;
}
//Entry
static class Entry<K, V> implements MyMap.Entry<K, V>{
K key;
V value;
hashMap.MyMap.Entry<K, V> nextEntry;
public Entry(K key, V value, hashMap.MyMap.Entry<K, V> nextEntry) {
super();
this.key = key;
this.value = value;
this.nextEntry = nextEntry;
}
@Override
public K getKey() {
// TODO Auto-generated method stub
return this.key;
}
@Override
public V getValue() {
return this.value;
}
@Override
public V setValue(V value) {
V ov=this.value;
this.value=value;
return ov;
}
@Override
public hashMap.MyMap.Entry<K, V> getNext() {
return this.nextEntry;
}
@Override
public hashMap.MyMap.Entry<K, V> setNext(hashMap.MyMap.Entry<K, V> next) {
hashMap.MyMap.Entry<K, V> oe=this.nextEntry;
this.nextEntry= next;
return oe;
}
}
}