源码
package com.collection.Map;
import java.util.Set;
public interface Map<K,V> {
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V v);
boolean equals(Object o);
int hashCode();
}
int size();
boolean isEmpty();
V put(K k,V v);
V get(K k);
V remove(Object k);
Set<Map.Entry<K, V>> entrySet();
boolean containsKey(Object k);
boolean containsValue(Object v);
}
package com.collection.Map;
import java.io.Serializable;
import java.util.AbstractSet;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
public class HashMap<K, V>
implements Map<K,V>, Cloneable, Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int DEFAULT_INITIAL_CAPACITY = 16; //hashMap 初始容量
private static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认--加载因子
static final int MAXIMUM_CAPACITY = 1 << 30;// 最大容量为2的30次方
int threshold;//容量的0.75倍 超过它 以2倍扩容方式扩容
//final float loadFactor;
transient Entry<K,V>[] table;
final float loadFactor;//加载因子
transient int modCount;//HashMap被改变的次数
transient int size;//宽度
private transient Set<com.collection.Map.Map.Entry<K, V>> entrySet = null;
public Set<com.collection.Map.Map.Entry<K, V>> entrySet() {
// TODO Auto-generated method stub
return entrySet0();
}
private Set<com.collection.Map.Map.Entry<K, V>> entrySet0() {
Set<com.collection.Map.Map.Entry<K, V>> es = entrySet;
return es != null ? es : (entrySet = new EntrySet());
}
private final class EntrySet extends AbstractSet<com.collection.Map.Map.Entry<K, V>>
{
@SuppressWarnings("unchecked")
public Iterator<com.collection.Map.Map.Entry<K, V>> iterator() {
return newEntryIterator();
}
@Override
public int size() {
// TODO Auto-generated method stub
return size;
}
}
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
}
public HashMap() {
// 设置“加载因子”为默认加载因子0.75
this.loadFactor = DEFAULT_LOAD_FACTOR;
// 设置“HashMap阈值”,当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
// 创建Entry数组,用来保存数据
table = new Entry[DEFAULT_INITIAL_CAPACITY];
}
public com.collection.Map.HashMap.EntryIterator newEntryIterator() {
// TODO Auto-generated method stub
return new EntryIterator();
}
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
@Override
public void remove() {
// TODO Auto-generated method stub
}
}
public int hash(Object k) {
int h;
return (k==null)?0:(h=k.hashCode())^(h>>>16);
}
int indexFor(int hash, int newLength) {
// TODO Auto-generated method stub
return hash&(newLength-1);
}
static class Entry<K,V> implements Map.Entry<K, V>
{
final K k;
V v;
Entry<K,V> next;
int hash;
public Entry(int h, K k, V v, Entry<K,V> n) {
this.k = k;
this.v = v;
this.next = n;
this.hash = h;
}
@Override
public K getKey() {
return k;
}
@Override
public V getValue() {
return v;
}
@Override
public V setValue(V v) {
V oldValue = this.v;
this.v = v;
return oldValue;
}
}
@Override
public int size() {
// TODO Auto-generated method stub
return size;
}
@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return size==0;
}
@Override
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return e==null?null:e.v;
}
private Entry<K,V> removeEntryForKey(Object key) {
int findHash = (key==null)?0:hash(key);
int i = indexFor(findHash,table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;
while (e!=null)
{
Entry<K,V> next = e.next;
Object k;
//当前对象等于删除对象
if(e.hash==findHash&&((k=e.k)==k||key!=null&&key.equals(k)))
{
modCount++;
size--;
if(prev==e)
{
table[i] = next;
}
else
{
prev.next = next;
}
return e;
}
prev = e;
e = next;
}
return null;
}
@Override
public boolean containsKey(Object k) {
return getEntry(k)!=null;
}
private Entry<K,V> getEntry(Object key) {
int hash = (key==null)?0: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.k)==k||key!=null&&key.equals(k)) )
{
return e;
}
}
return null;
}
@Override
public boolean containsValue(Object v) {
if(v==null)
{
return containsNullValue(v);
}
Entry[] tab = table;
for(int i=0; i<tab.length; i++)
{
for(Entry<K,V> e = tab[i]; e!=null; e= e.next)
{
if(v.equals(e.v))
{
return true;
}
}
}
return false;
}
private boolean containsNullValue(Object value) {
Entry<K, V>[] tab = table;
for (int i=0; i<tab.length;i++)
{
for(Entry<K,V> e = tab[i];e!=null; e= e.next)
{
if(e.v==null)
{
return true;
}
}
}
return false;
}
@Override
public V put(K key,V value)
{
if(key==null)
{
return putForNullKey(value);
}
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e!=null; e = e.next )
{
Object k = null;
if(e.hash==hash && ((k=e.k) == key)||(key.equals(k)) )
{
V olaValue = e.v;
e.v = value;
return olaValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
//单独处理 键值为null的
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0];e!=null;e = e.next )
{
if(e.getKey()==null)
{
V oldValue = e.v;
e.v = value;
return oldValue;
}
}
modCount++;
//
addEntry(0,null,value,0);
return null;
}
private void addEntry(int h, K key, V value, int j) {
Entry<K,V> e = table[j];
//int h, K k, V v, Entry<K,V> n-----总是让新的entry 指向 旧的entry
table[j] = new Entry<K,V>(h, key,value,e);
//threshold 超过扩充值
if(size++>threshold)
{
resize(2*table.length);
}
}
private void resize(int i) {
Entry[] oldTable = table;
int oldCapaCity = oldTable.length;
//容量 已经达到最大值
if(oldCapaCity > MAXIMUM_CAPACITY)
{
// 设置为Integer 最大值
threshold = Integer.MAX_VALUE;
return ;
}
Entry[] newTbale = new Entry[i];
//oldtbale 旧内容copy到 newTable
transfer(newTbale);
}
private void transfer(Entry[] newTable) {
Entry[] copyFrom = table;
int newLength = newTable.length;
for (int j=0; j<table.length; j++)
{
Entry e = copyFrom[j];
if(e!=null)
{
copyFrom[j] = null;
do
{
Entry next = e.next;
// 根据新的容量计算e在新数组中的位置
int i = indexFor(e.hash, newLength);
// 将e插入到newTable[i]指向的链表的头部
e.next = newTable[i];
newTable[i] = e;//给新数组赋值
//拿到下一个继续执行程序
e = next;
}
while(e!=null);
}
}
}
public V get(Object key)
{
if(key==null)
{
return getForNullKey();
}
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e!=null; e = e.next )
{
Object k = null;
if(hash==e.hash&&( (k=e.k)==key) || (key.equals(k)) )
{
return e.v;
}
}
return null;
}
private V getForNullKey() {
for (Entry<K,V> e = table[0];e!=null;e = e.next)
{
if(e.k == null)
{
return e.v;
}
}
return null;
}
}
1.jdk HashMap 设计思路
以下内容是我结合了网友的资料 自己整理下
http://blog.youkuaiyun.com/lyandyhk/article/details/51147012
https://www.zhihu.com/question/20733617
1.扰动函数
以下这段代码叫做扰动函数 jdk8有所优化
jdk 1.7
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
jdk 1.8
static int hash(int h) {
int h;
return (key==null):0:(key.hashCode())^(h>>16);
}
从上面代码看出来key.hashCode 是int类型 长度-2147483648到2147483648 显然 这个长度数组 内存是放不下 40亿
所以这个散列值不能直接拿来用,用之前还要对数组的长度取摸运算
static int indexFor(int h, int length) {
return h & (length-1);
}
为什么数组的长度要是2的整数幂? 因为设计组成的二进制长度只有低位掩码
(HashMap的初始大小和扩容都是以2的次方来进行的,换句话说length-1换成二进制永远是全部为1,
比如容量为16,则length-1为1111)
h中对应位取0,对应位结果为0,h对应位取1,对应位结果为1。这样就有两个结果),但是如果length-1中某一位为0,则不论h中对应位的数字为几,
对应位结果都是0,这样就让两个h取到同一个结果,这就是hash冲突了,恰恰length-1又是全部为1的数,所以结果自然就将hash冲突最小化了
列如初始长度16-1
15 的二进制数00000000 00000000 00001111 假设与其他二进制数做&运算
列如下面做位运算
11110000 00000000 00001111
00000000 00000000 00001111
0111结果就是保留低四位 但是这样做 还是有碰撞
扰动函数在这个时候 价值就体现出来
h = hashCode()
hash码 高位16 和地低位的16 做了一个异或 以此来加大低位的随机性
但明显Java 8觉得扰动做一次就够了,做4次的话,多了可能边际效用也不大,所谓为了效率考虑就改成一次了。
h%length与h&(length-1)得到是同一个值
1.length(2的整数次幂)的特殊性导致了length-1的特殊性(二进制全为1)
2.位运算快于十进制运算,hashmap扩容也是按位扩容,所以相比较就选择了后者