1,首先看到put方法
public V put(K key, V value) { // 在其中调用了hash方法 return putVal(hash(key), key, value, false, true); } static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
2,往里追,putVal方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node[] tab; Node p; int n, i; // 进入第一层判断,判断是否表是否为null, // 则会去调用resize()方法,完成对table的初始化 // 其在resize里面做的一个事情,加载因子*当前数组的容量, // 默认16,所以就是 0.75 * 16 = 12,得出一个临界值 // 则临界值,是当我们容量到达临界值时,完成的一个扩容的过程 if ((tab = table) == null || (n = tab.length) == 0) // 初始化,感兴趣的小伙伴,可以往resize()里面追 n = (tab = resize()).length; // 通过hash过后得到一个索引位置,判断当前位置是否有值, // 如果没有值,则创建一个新的节点 if ((p = tab[i = (n - 1) & hash]) == null) // 确定当前位置没有值 // 首次加入话,必定会加进去的 tab[i] = newNode(hash, key, value, null); else {// 当前位置有值 // 如果当前值,则会进行多次判断 Node e; K k; // 首先第一次判断,判断当前索引的第一个位置的hash值是否跟 // 我正在添加进去的hash值是否相同,如果相同则 p 赋值给 e // 之后就会完成值的替换 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) // 判断当前是否为树型 // 如果为树形,则会已树形的方式添加 e = ((TreeNode )p).putTreeval(this, tab, hash, key, value); else { // for 死循环 for (int binCount = 0; ; ++binCount) { // p.next赋值给e 判断是否为null, 也就是说判断下个节点 // 是否有值 if ((e = p.next) == null) { // 如果确实等于null 则在当前p的下个节点创建 // 一个新的节点 p.next = newNode(hash, key, value, null); // 判断链表长度>=8 table长度>=64 转换为红黑树 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st //会去调用treeifyBin方法,则不会马上进行 //树化,在treeifyBin中判断了table.length //如果满足两个条件才会进行红黑树化 treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } // 其当前判断,也就是我们上面所说的,如果满足当前条件 // 则意味着添加失败,因为它们在当前找到了那个值,并赋值给了e if (e != null) { // existing mapping for key // 原来的旧值提取出来 V oldValue = e.value; //onlyIfAbsent 传进来就是false,取反则为true if (!onlyIfAbsent || oldValue == null) // e.value = value; 这意味着当前当前新的value给 // 到了e.value ,从而发生了替换 // 这就是为什么HaspMap value 可以重复,如果key重复 // 则key的value会被替换 e.value = value; afterNodeAccess(e); // 空实现方法,交给子类去实现的 //如果返回有值,则是添加失败,返回null,则添加成功 return oldValue; // 添加失败 } } ++modCount;// 修改次数加加 // 当前table容量值 是否大于 临界值 if (++size > threshold) resize(); // 如果满足 开始扩容 afterNodeInsertion(evict); // 空实现方法,交给子类去实现的 return null;// 添加成功 }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)