0001

hashMap 源码 简单解析。


public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{

/**
* The default initial capacity - MUST be a power of two.
*2的次方 必须是 默认初始化的大小 是16
*/
static final int DEFAULT_INITIAL_CAPACITY = 16;

/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*左移位 最大值 1<<30 = 1 073 741 824 2 的30次方
*2<<3 2*2的3次方
*/
static final int MAXIMUM_CAPACITY = 1 << 30;

/**
* The load factor used when none specified in constructor.
*默认负载因子 (当没有指定负载因子时 采用默认的)
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;

/**
* The table, resized as necessary. Length MUST Always be a power of two.
*数组的长度必须为2 的次幂
*/
transient Entry[] table;

/**
* The number of key-value mappings contained in this map.
*/
transient int size;

/**
* The next size value at which to resize (capacity * load factor).
* 数组扩容时的长度是根据负载因子和默认长度计算出来的 eg:默认loadFactor = 0.75 ,catacity = 16 则当数组容量超过12时就进行扩容
*容量为capacity 的2倍 即2的次幂。
* @serial
*/
int threshold;

/**
* The load factor for the hash table.
*为数组准备的负载因子 可以自定义大小
* @serial
*/
final float loadFactor;

/**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the HashMap fail-fast. (See ConcurrentModificationException).
*记录hashMap 被修改的次数,每次都是加一操作。
*/
transient volatile int modCount;


//静态类 用来存放参数
static class Entry<K,V> implements Map.Entry<K,V> {
final K key; ----key存放键值
V value; ----存放键
Entry<K,V> next; 指向下一个对象,用来当位置重复时做链表用
final int hash; ----存放hash 值, 这里不是hashcode 是 通过hashmap的hash算法得到的hash值 但是是和hashcode有关
如果hashcode相等,则此值也是相同的

/**


/**
* Offloaded version of put for null keys
*/
private V putForNullKey(V value) {
/×××
key==null时调用



××/
for (Entry<K,V> e = table[0]; e != null; e = e.next) {//在0索引位置开始向后循环查找查找 注意next 链表结构
//如果这个地方有null 的key 则替换掉,否则调用下面的方法
//注意:null的key 都是存储在0索引位置的,即table数组的第一位如果有链表则向下连
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);//这个方法是存储null 的key的

return null;
}


/**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
//buckectIndex 是要存放value值在数组中的位置。
//首先把backetIndex位置的数取出来,指向e
Entry<K,V> e = table[bucketIndex];

将backetIndex 位置存入新的entry 对象,此对象把原先的entry对象放到了next里
根据最近使用的数据在不远的将来还会在使用的原则,把新的entry对象放到了此处索引位置的最上面,以前的老的entry对象向下链接。
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
判断数组的长度如果超出了threshold= capacity*loadFactory 16*0.75 如果超过或者相等就会扩容数组为原来的2倍
if (size++ >= threshold)
resize(2 * table.length);
}

/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*如果map里有key(通过e.hash == hash && ((k = e.key) == key || key.equals(k)) 判断的) 则用新值替换老的值,并把oldvalue返回
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*上面的一段大体意思是 key 关联指定的value 。或者value去关联指定的key
*/
public V put(K key, V value) {
if (key == null)
/××

先说说key==null吧
如果key==null 调用putFor NUllKey 方法 参数为value



×××/
return putForNullKey(value);


int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);

//判断此位置的链表上是否有这个key,如果有 则替换没有就调用add方法添加
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

modCount++;
//此处和上面是一样的,记住entry对象里存了hash值,key,value,和数组的索引位置
addEntry(hash, key, value, i);
return null;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值