jdk_Collection_HashMap源码

来源:互联网 发布:网络监控传输距离 编辑:程序博客网 时间:2024/05/29 12:20

源码


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.csdn.net/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类型 长度-21474836482147483648 显然 这个长度数组  内存是放不下 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扩容也是按位扩容,所以相比较就选择了后者



0 0
原创粉丝点击