做了两年的java,感觉技术上没多大提升,特别是呆了一年外企,整理感觉自己都萎靡,不爱学习!
所以,写个帖子记下在网上看到的东西以及自己要去学习的内容!努力奋斗!1.HashMap的实现--------------------<在看> 1.1 HashMap 的默认size是16,默认临界值是 12,默认的基数0.75。 1.2 HashMap 的最大size是1<<30 1.3 HashMap 中 transfer方法理解:void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { Entrye = src[j];//标记1 if (e != null) { src[j] = null;//标记2 do { Entry next = e.next;//标记3 int i = indexFor(e.hash, newCapacity);//标记4 e.next = newTable[i];//标记5 newTable[i] = e;//标记6 e = next;//标记7 } while (e != null); } } }
标记1:从Entry 数组中获取到 oldTable中需要往newTable 插入的entry实例e。
标记2:回收oldTable的内存。 标记3:使用临时变量存储e.next的值,以便下次获取链表的下个需要遍历的值,直到e.next的值为空。 标记4:根据e的hash值和新表中的容量计算e需要放置在新数组中的index值。 标记5:把新数组index位置的值传递给e.next. 标记6:把e放置在新数组index的位置下。 标记7:重新设置e的值,把老数组e的next值传递给e.继续下一轮循环,直到e的next为空。 1.4 HashMap 中 put 方法:public V put(K key, V value) { if (key == null) return putForNullKey(value); //根据hash算法获取需要插入数据的hash值 int hash = hash(key.hashCode()); //根据hash值,计算将要插入数组的index值 int i = indexFor(hash, table.length); //如果该index下,存在链表值,遍历该链表,对比 //链表中的每一个entry的实例的hash值和key //是否和需要插入的key和key的hash值相同。 //如果相同:跟新原entry下的value;保持key,index和hash值不 //变。 //如果不相同:把新纪录插入到数组中。 for (Entrye = 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++; addEntry(hash, key, value, i); return null; }
1.5 HashMap中的addEntry方法:
void addEntry(int hash, K key, V value, int bucketIndex) { Entrye = table[bucketIndex]; table[bucketIndex] = new Entry (hash, key, value, e); //如果数组table的长度大于临界值,将table进行扩容,长度为原来的 //两倍。 if (size++ >= threshold) resize(2 * table.length); }
1.6 HashMap中的静态内部类Entry:
static class Entryimplements Map.Entry { final K key; V value; Entry next; final int hash; /** * h:新创建的entry实例的hash值。 * k:键值 * v:值 * n:链表中但前entry实例的下一个entry的值。 */ Entry(int h, K k, V v, Entry n) { value = v; next = n; key = k; hash = h; } public final K getKey() { return key; } public final V getValue() { return value; } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } public final boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; } return false; } public final int hashCode() { return (key==null ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode()); } public final String toString() { return getKey() + "=" + getValue(); } void recordAccess(HashMap m) { } void recordRemoval(HashMap m) { } }
1.7 HashMap中的remove()方法:
final EntryremoveEntryForKey(Object key) { //获取hash值,如果key是null,hash值为0. int hash = (key == null) ? 0 : hash(key.hashCode()); //获取该key的下标值。 int i = indexFor(hash, table.length); Entry prev = table[i]; Entry e = prev; while (e != null) { Entry next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e) //移动数组,用需要删除数组后一位置的值覆盖当前位置 table[i] = next; else //把需要删除的值,用当前链表中的下一个值 //进行覆盖,依次用下一个覆盖上一个,直到 //需要删除纪录后的每一数据都向前移动一位。 prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; }
有代码可得知:hashmap的删除不知是单单的把需要删除的纪录内存释放(设置为null)。而是
移动需要删除纪录后的每一个元素来覆盖前元素,释放最后一个值。 1.8 HashMap 中的get()方法:public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entrye = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
从上面代码可以得知,当key为空的时候,hashmap从table[0]的位置获取专门存取null键的位置获取值,key不为空的时候,根据传入 key的hash值,获取index值(数组下标),然后 遍历该index下的entry链表,比对该hash值下所有的key,如果有key和传入的key相同,
获取该key下的value. 1.9 HashMap的结构图(见附件)