您的位置:首页 > 编程语言 > Java开发

HashMap源码分析 基于JDK1.6

2017-06-08 20:59 791 查看
public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable, Serializable {

static final int DEFAULT_INITIAL_CAPACITY = 16; //系统默认初始容量

static final int MAXIMUM_CAPACITY = 1 << 30; //系统默认最大容量

static final float DEFAULT_LOAD_FACTOR = 0.75f; //系统默认初始加载因子

transient Entry[] table; //用于存储的表

transient int size; //当前map中key-value映射数

int threshold; //当前阈值

final float loadFactor; //哈希表加载因子

transient volatile int modCount; //确保使用迭代器时,HashMap并未更改
/*---------------------------------构造函数----------------------------------------*/

/**
* 默认构造函数
* 构造一个初始容量为16和默认加载因子为0.75的空的HashMap
*/
public HashMap() {

this.loadFactor = DEFAULT_LOAD_FACTOR;//哈希表加载因子为默认加载因子
this.threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);//设置阈值12 = 16 * 0.75,当HashMap的size达到此阈值时,HashMap就该扩容
table = new Entry[DEFAULT_INITIAL_CAPACITY];//创建一个默认容量16的空数组
init();
}

/**
* 带指定初始容量和指定加载因子的构造函数
* 构造一个带指定初始容量和指定加载因子的空的HashMap
*/
public HashMap(int initialCapacity, float loadFactor) {

//指定初始容量小于0 抛错
if (initialCapacity < 0)
throw new IllegalArgumentException("Illeagal initial capacity : " + initialCapacity);

//指定初始容量大于系统最大容量,则初始容量为最大容量
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;

//加载因子小于0或为naN 抛错
if (loadFactor < 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " + loadFactor);

//寻找一个2的k次幂capacity恰好大于initialCapacity
int capacity = 1;
while (capacity < initialCapacity) {

capacity <<= 1;
}

//设置哈希表的加载因子为指定的加载因子
this.loadFactor = loadFactor;

//设置阈值
this.threshold = (int) (capacity * loadFactor);

//创建一个capacity长度的数组用于保存数据
table = new Entry[capacity];

//开始初始化
init();

}

/**
* 带指定初始容量的构造函数
* 构造一个带有指定初始容量和默认加载因子0.75的空的HashMap
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);

}

/**
* 带指定映射关系的狗构造函数
* 构造一个映射关系与指定的map相同的HashMap
*/
public HashMap(HashMap<? extends K, ? extends V> m) {

//调用带指定容量和默认加载因子的构造函数 容量为指定map的容量与默认初始容量中较大者
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);

putAllForCreate(m);
}

/*----------------------------------方法区------------------------------------*/

//定义一个空方法用于对未来子对象的扩展  该方法用于初始化之后  插入元素之前
public void init() {

}

/**
* 方法:二次hash计算
* 预处理hash值,对key的hashCode进行二次hash计算,避免较差的离散hash序列,导致哈希桶没有充分利用
*/
static int hash(int h) {

h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}

/**
* 方法:返回hash值对应的索引
* 通过对hash值的计算,获取实际的存储位置
*/
static int indexFor(int hash, int length) {

return hash & (length - 1);
}

/**
* 方法: 返回size
* 返回当前map的key-value映射数,也就是当前的size
*/
public int size() {

return size;
}

/**
* 方法: 是否为空
* 判断HashMap是否为空 size为0时返回false
*/
public boolean isEmpty() {

return size == 0;
}

/*------------------------------------核心方法区---------------------------------------------*/

/**
* 方法: 返回key对应value值
* 返回指定键(key)所映射的值(value),如果该键(key)不对应任何映射关系,返回null
*/
public V get(Object key) {

//将key分为null,不为null的情况区别对待 此处就是HashMap能够存储(null,null)所做的处理
//如果key为null
if (key == null) {

return getForNullKey();
}
//如果key不为null
//对key的hashcode值进行二次hash计算预处理
int hash = hash(key.hashCode());
//根据hash值获取对应的桶 然后在桶内遍历查找
for (Entry<K, V> entry = table[indexFor(hash, table.length)]; entry != null; entry = entry.next) {

Object k = entry.key;

//如果hash值相等  并且key相等则证明这个桶内的东西是我们想要的
//hash值是根据key的hashcode进行复杂计算得到的,因此key相同的话hash一定相同,因此通过indexFor查找到的索引位置也一定相同
//但是索引位置相同,并不代表桶中的key对应hash值相同,因为不同hash值经过取膜计算后,会散到同同一索引位置的桶中
//因此先通过判断hash值是否相同,筛选掉不符合的entry,可以提高性能,因为equals方法效率很低
if (entry.hash == hash && (k == key || key.equals(k)))
return entry.value;

}

//桶内所有元素都找遍 没有找到key对应的value,代表该map中不存在该映射 因此返回null
return null;

}

/**
* 方法: 获取null对应value
* 如果key为null,通过该方法获取对应的value值
*/
private V getForNullKey() {

//遍历table[0]桶内所有的元素 默认null对应的hash值所映射的索引位置为table[0]
for (Entry<K, V> entry = table[0]; entry != entry; entry = entry.next) {

if (entry.key == null)
return entry.value;
}
//没找到则返回null
return null;
}

/**
* 方法: 判断是否包含指定键对应映射关系
* 判断是否包含指定键的映射关系 存在返回true 不存在返回false
*/
public boolean containsKey(Object key) {

return getEntry(key) != null;
}

/**
* 方法: 通过key获取value值
* 通过给定的key,求对应的value值,如果存在返回value  不存在 返回null
*/
final Entry<K, V> getEntry(Object key) {

//获取hash值  key为null时 hash为0 不用进行二次hash计算
int hash = (key == null) ? 0 : hash(key.hashCode());

//得到对应hash值的桶
for (Entry<K, V> entry = table[indexFor(hash, table.length)]; entry != null; entry = entry.next) {

Object k;
//如果hash值相等,并且key相等,那么该value就是我们要找的
if (entry.hash == hash && ((k = entry.key) == key || (key != null && key.equals(k)))) {
return entry;
}
}

return null;
}

/**
* 方法: 在map中放置指定的键值对
* 在map中关联指定的值与指定的键 如果就得映射关系存在,则替换掉旧的value值
*/
public V put(K key, V value) {

//如果key为null时用putForNullKey来专门存放
if (key == null)
return putForNullKey(value);
//获取对应的hash值
int hash = hash(key.hashCode());
//获取对应的索引值
int i = indexFor(hash, table.length);
//在对应的桶中遍历
for (Entry<K, V> entry = table[i]; entry != null; entry = entry.next) {

Object k;
//如果hash相同并且key相同
if (entry.hash == hash && ((k = entry.key) == key || key.equals(k))) {

//获取旧value
V oldV
4000
alue = entry.value;
//替换旧的value
entry.value = value;
entry.recordAccess(this);
//返回旧value
return oldValue;
}

}

modCount++;
//在桶中没有找到对应key值,代表map中没有对应映射关系,因此就关联此映射关系
addEntry(hash, key, value, i);
return null;

}

/**
* 方法: 在map中放置key为null的键值对
*/
private V putForNullKey(V value) {

//遍历table[0]的所有的桶
for (Entry<K, V> entry = table[0]; entry != null; entry = entry.next) {

//如果key为null
if (entry.key == null) {
//获取旧的value值
V oldValue = entry.value;
//替换新的value值
entry.value = value;
return oldValue;
}

}

modCount++;
//在桶中没有找到对应null值,代表map中没有对应映射关系,因此就关联此映射关系
addEntry(0, null, value, 0);
return null;

}

/**
* 方法: 判断是否创建新桶
*/
private void putForCreate(K key, V value) {

//获取key对应的hash值
int hash = (key == null) ? 0 : hash(key.hashCode());
//获取hash值对应的索引值
int i = indexFor(hash, table.length);

//遍历桶
for (Entry<K, V> entry = table[i]; entry != null; entry = entry.next) {
Object k;
//如果有hash相同 且key相同 则不需要创建新桶
if (entry.hash == hash && ((k = entry.key) == key || (key != null && key.equals(k)))) {
return;
}
}
//否则就创建新的桶
createEntry(hash, key, value, i);

}

/**
* 方法: 根据map创建对应的桶
*/
private void putAllForCreate(Map<? extends K, ? extends V> map) {
for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = map.entrySet().iterator(); i.hasNext(); ) {
Map.Entry<? extends K, ? extends V> e = i.next();
putForCreate(e.getKey(), e.getValue());
}

}

/**
* 方法: 扩容
*/
void resize(int newCapacity) {

//保存旧的table数组
Entry[] oldTable = table;
//保存旧数组的容量
int oldCapacity = oldTable.length;
//如果就容量已经达到系统默认最大容量 那么将阈值调整为整形最大值 然后退出
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}

//根据新容量创建一个新table数组
Entry[] newTable = new Entry[newCapacity];
//将table转换成newTable
transfer(newTable);
//将table设置为newTable
table = newTable;
//设置新的阈值为新容量 * 加载因子
threshold = (int) (newCapacity * loadFactor);

}

/**
* 方法: 将旧table转为新table
*/
private void transfer(Entry[] newTable) {
//得到旧的table
Entry[] src = table;
//得到新的容量
int newCapacity = newTable.length;
//遍历旧的table: src中的所有桶
for (int j = 0; j < src.length; j++) {

//取出每一个桶
Entry<K, V> entry = src[j];
if (entry != null) {
src[j] = null;
do {

Entry<K, V> next = entry.next;
//在新的table中寻找新的索引
int i = indexFor(entry.hash, newCapacity);
//尾插法
entry.next = newTable[i];
newTable[i] = entry;
entry = next;

} while (entry != null);
}
}
}

/**
* 方法: 将指定map中的映射复制到此map中
*/
public void putAll(Map<? extends K, ? extends V> map) {

//需要复制的映射的数量
int numKeysToBeAdded = map.size();
if (numKeysToBeAdded == 0)
return;

//如果需要复制的映射关系大于当前map的阈值
if (numKeysToBeAdded > threshold) {
//重新计算当前map的容量
int targetCapacity = (int) (numKeysToBeAdded / loadFactor + 1);
if (targetCapacity > MAXIMUM_CAPACITY)
targetCapacity = MAXIMUM_CAPACITY;
//获取当前table数组的容量
int newCapacity = table.length;
while (newCapacity < targetCapacity)
newCapacity <<= 1;
if (newCapacity > table.length)
resize(newCapacity);
}

for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = map.entrySet().iterator(); i.hasNext(); ) {
Map.Entry<? extends K, ? extends V> e = i.next();
put(e.getKey(), e.getValue());
}
}

/**
* 方法: 移除映射关系
* 从此映射中移除指定的映射关系 并返回移除映射的值
*/
public V remove(Object key) {

Entry<K, V> entry = removeEntryForKey(key);
return (entry == null) ? null : entry.value;
}

/**
* 方法: 根据对应key删除对应的映射关系
*/
final Entry<K, V> removeEntryForKey(Object key) {

int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
//找到对应的桶
Entry<K, V> prev = table[i];
Entry<K, V> entry = prev;

//遍历该桶
while (entry != null) {
Entry<K, V> next = entry.next;
Object k;
if (entry.hash == hash && ((k = entry.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == entry)
table[i] = next;
else
prev.next = next;

return entry;

}
prev = entry;
entry = next;
}

return entry;//返回null
}

/**
* 方法: 根据key删除映射关系
*/
final Entry<K, V> removeMapping(Object object) {

if (!(object instanceof Map.Entry))
return null;
//将object转为Map.Entry
Map.Entry<K, V> entry = (Map.Entry<K, V>) object;
//得到对应的key
Object key = entry.getKey();
//得到key对应的hash
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
Entry<K, V> prev = table[i];
Entry<K, V> e = prev;
while (e != null) {
Entry<K, V> next = e.next;
if (e.hash == hash && e.equals(entry)) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
}
prev = e;
e = next;
}
return e;
}

/**
* 方法: 移除所有映射关系
*/
public void clear() {
modCount++;
Entry[] tab = table;
for (int i = 0; i < tab.length; i++)
tab[i] = null;
size = 0;
}

/**
* 方法: 判断是否存在指定的值对应的映射关系
* 如果存在一个或多个key映射指定value 返回true
*/
public boolean containsValue(Object value) {

//如果value为null 调用专门的方法
if (value == null)
return containsNullValue();
Entry[] tab = table;
//遍历table数组
for (int i = 0; i < tab.length; i++)
for (Entry entry = tab[i]; entry != null; entry = entry.next)
if (value.equals(entry.value))
return true;

return false;

}

/**
* 方法: 判断是否存在value为null的映射关系
*/
private boolean containsNullValue() {
Entry[] tab = table;
for (int i = 0; i < tab.length; i++)
for (Entry entry = tab[i]; entry != null; entry = entry.next)
if (entry.value == null)
return true;

return false;
}

/**
* 方法: 浅表拷贝
* 返回hashmap的浅表副本  不复制键和本身
*/
public Object clone() {
HashMap<K, V> result = null;
try {
result = (HashMap<K, V>) super.clone();
} catch (CloneNotSupportedException e) {

}
result.table = new Entry[table.length];
result.modCount = 0;
result.size = 0;
result.init();
result.putAllForCreate(this);
return result;
}

/*--------------------------内置Class输入对象-------------------------------*/
static class Entry<K, V> implements Map.Entry<K, V> {

final K key;//键

V value;//值

Entry<K, V> next;//下一个节点

final int hash;

//构造函数
Entry(int h, K k, V v, Entry<K, V> n) {
value = v;
next = n;
key = k;
hash = h;
}

//返回key
public final K getKey() {
return key;
}

//返回value
public V getValue() {
return value;
}

//设置value  返回旧值
public final V setValue(V newValue) {
V oldValue = this.value;
this.value = newValue;
return oldValue;
}

//是否相同
@Override
public boolean equals(Object object) {

if (!(object instanceof Map.Entry))
return false;

//将object转化成Map.Entry
Map.Entry entry = (Map.Entry) object;

//比较key和value值
Object key1 = this.getKey();
Object key2 = entry.getKey();

if (key1 == key2 || key1 != null && key1.equals(key2)) {//键相等

Object value1 = this.getValue();
Object value2 = entry.getValue();

if (value1 == value2 || value1 != null && value1.equals(value2))//值相等
return true;
}

return false;
}

//重写hashCode()
@Override
public int hashCode() {
return ((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode());
}

//

@Override
public String toString() {

return getKey() + "=" + getValue();
}

// 使用该方法证明该key已经在该map中
void recordAccess(HashMap<K, V> map) {
}

// 该方法记录该key已经被移除了
void recordRemoval(HashMap<K, V> map) {
}
}

/*----------------------HashMap内方法-----------------------------------*/

/**
* 方法: 添加新的节点
*/
private void addEntry(int hash, K key, V value, int bucketIndex) {

// 保存对应table的值
Entry<K, V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K, V>(hash, key, value, e);
// 如果当前size大于等于阈值
if (size++ >= threshold)
// 调整容量 HashMap采用两倍扩容
resize(2 * table.length);
}

/**
* 方法: 创建新的节点
*/
void createEntry(int hash, K key, V value, int bucketIndex) {

Entry<K, V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K, V>(hash, key, value, e);
size++;
}

@Override
public Set<Map.Entry<K, V>> entrySet() {
return null;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hashmap 源码