public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { //默认初始化大小,若是没有给初始化值的话,大小就是16(2的n次幂),后面的扩容也是2的N次幂 static final int DEFAULT_INITIAL_CAPACITY = 16; //最大容量,2的30次方 static final int MAXIMUM_CAPACITY = 1 << 30; //系统默认的负载因子(没懂其意义) static final float DEFAULT_LOAD_FACTOR = 0.75f; //存放数据的实体(重要) transient Entry[] table; //实际存放数据的量 transient int size; //阈值(没懂),大小为Entry的长度*loadFactor int threshold; //哈希表的负载因子(没懂) final float loadFactor; //修改次数 transient volatile int modCount; //构建函数(初始化容量和hash表的负载) public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0)//小于零抛异常 throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); //保证Entry[]的大小不会超过最大值 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // 初始化各个值,除非initialCapacity恰好是2的N次幂,不然初始化Entry[]的容量确定比传入的initialCapa //city值要大,而且应该是比initialCapacity大的第一个2的N次幂 int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); table = new Entry[capacity]; init(); } //构造函数 public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } //构造函数 public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); } //构造函数 public HashMap(Map<? extends K, ? extends V> m) { //初始化新map的大小等参数 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); //copy数据,把m中的数据复制到新的集合里面,putAllForCreate的细节在方法内解析 putAllForCreate(m); } void init() { } //一个自定义的hash算法 static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } //自定义的算法,返回的结果就是在Entry[]数组中的位置 static int indexFor(int h, int length) { return h & (length-1); } //返回具体数据的数量 public int size() { return size; } //判断是否为空 public boolean isEmpty() { return size == 0; } //获取数据 public V get(Object key) { //key==null的话就找寻是否有key为空值对应的value if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); //这个for循环挺有意思,因为hashmap是数组+链表,因此此循环其实是找到在Entry[]上的位置,而后循环这个 //位置上的链表,很像XY轴,定位到X轴后再循环在X轴上Y轴的数据 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; //e内存储的hash要和传入的key的hash值相同(e内存储的hash就是e中key的hash值),而且e中的key要和 //传入的key相等,此时返回e的value if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } //不然为空 return null; } //返回空键的值,按照以前的算法,传入的key为空的时候,因为存放数值的函数处理的时候把key为空时放到0处,因此 //搜寻地址在0处的链表就好了 private V getForNullKey() { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) return e.value; } return null; } //看是否有哪一个Entry内的key等于传入的key,有的话为true,不然为false public boolean containsKey(Object key) { return getEntry(key) != null; } //获取key对应的Entry final Entry<K,V> getEntry(Object key) { //key为空的时候直接给0,不然计算会抛空指针异常 int hash = (key == null) ? 0 : hash(key.hashCode()); //遍历整个链表 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; //e的key与传入的相等就返回此Entry if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } //不然为空 return null; } //存入数据 public V put(K key, V value) { //key为空的时候特殊处理 if (key == null) return putForNullKey(value); //计算key的hash值 int hash = hash(key.hashCode()); //经过key定位到数组的位置 int i = indexFor(hash, table.length); //遍历i上的链表 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //若是找到有同样的(同一个key),就替换此处的值,只替换此处Entry内的value属性值 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; //不知道干啥的 e.recordAccess(this); //返回之前的value PS:有些API手册上没注明会返回原来的值 return oldValue; } } //修改次数+1 modCount++; //发现Entry[]的i位置上的链表没有一样的key,就在i上添加值,具体的添加细节看下面的方法注释 addEntry(hash, key, value, i); //而后返回NULL return null; } //key为空的时候存放value private V putForNullKey(V value) { //遍历Entry[]0处的链表 for (Entry<K,V> e = table[0]; e != null; e = e.next) { //功能同上个方法 if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } //同上,0处没发现有等于null的key就添加一个值 modCount++; addEntry(0, null, value, 0); return null; } //最后一个构造函数new Map(map)的业务方法 private void putForCreate(K key, V value) { //若key为空仍然用0,不然就计算出hash值 int hash = (key == null) ? 0 : hash(key.hashCode()); //在Entry[]上的位置 int i = indexFor(hash, table.length); //遍历此位置上的链表 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //替换value if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { e.value = value; return; } } //没找到同样的key就建立一个Entry createEntry(hash, key, value, i); } //第四个构造函数直接调用的方法 private void putAllForCreate(Map<? extends K, ? extends V> m) { //用迭代器(感受能够用while(i.hasNext())),遍历m内的全部元素 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { Map.Entry<? extends K, ? extends V> e = i.next(); //把每一个迭代的值用如下方法处理,具体看下面方法的注释 putForCreate(e.getKey(), e.getValue()); } } //从新修改map的大小 void resize(int newCapacity) { //将当前的Entry[]拿出来 Entry[] oldTable = table; //旧数组的长度(数组的长度,不是数值的数量) int oldCapacity = oldTable.length; //若就数组的长度是最大值 if (oldCapacity == MAXIMUM_CAPACITY) { //修改临界值 threshold = Integer.MAX_VALUE; return; } //用新的传入长度构建一个Entry[] Entry[] newTable = new Entry[newCapacity]; //复制,把原来Entry[]内的数据都复制到新的Entry[]内 transfer(newTable); //替换掉旧的数组 table = newTable; //修改阈值 threshold = (int)(newCapacity * loadFactor); } //复制,把原来Entry[]内的数据都复制到新的Entry[]内 void transfer(Entry[] newTable) { //把当前数组(旧数组)“存盘” Entry[] src = table; //新数组的长度 int newCapacity = newTable.length; //遍历旧的数组 for (int j = 0; j < src.length; j++) { //旧数组的数据“存盘” Entry<K,V> e = src[j]; if (e != null) { //清空位置为j上的全部数据 src[j] = null; //开始循环以前j位置上的链表 do { //这个循环有点意思,文字表述有点困难,后续补图 //首先Entry是个链表,它内部的next指向另外一个Entry //理解以上的东西后,如下循环以这个链表上的第一个数据为例: //先把链表从第二个值开始的链表(当前循环值的后一个)“存盘”(1),而后在新的数组上计算出此链表 //上第一个值应该存放的位置i(2),而后把这个数组i上的数据拼接到此链表第一个数据以后,造成一个新 //的链表(3),再把拼接后的链表放到数组的i处(4),而后把从第二个值开始的链表赋给e(5),接下 //来就是继续循环,知道e==null为止(6)。而后再循环此数组上的下一个链表 Entry<K,V> next = e.next; //1 int i = indexFor(e.hash, newCapacity);//2 e.next = newTable[i];//3 newTable[i] = e;//4 e = next;//5 } while (e != null);//6 } //copy完以后数据的位置是有变化的,先不说在新数组上的位置变了,连在链表上的位置也变了 //总体的调整容量思路就是:建立一个具备新容量的数组,而后把旧数组的值所有复制到新的数组里面,同时清 //空旧数组的值(消除指针),等待回收 } } //把m的值copy到原来的数组内,若是key相同就替换掉原来的value,若是key不一样则加入 public void putAll(Map<? extends K, ? extends V> m) { int numKeysToBeAdded = m.size(); //传入的m为空,就返回空 if (numKeysToBeAdded == 0) return; //若是m的size大于当前的阈值,则经过计算扩大后的m.size()会不会比table.length大,若是大则执行后续操做 //ps:小小的计算了一下,发现只要m.size>阈值,newCapacity < targetCapacity就几乎是恒成立的 //大概就是4/3*m.size<table.length<4/3*m.size+1,在这种状况下newCapacity 才可能大于targetCapacity if (numKeysToBeAdded > threshold) { int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length; while (newCapacity < targetCapacity) //给原来的table.length扩容 newCapacity <<= 1; if (newCapacity > table.length) //调整容量的大小 resize(newCapacity); } //开始迭代 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { Map.Entry<? extends K, ? extends V> e = i.next(); //把迭代的值扔进原来的put中,执行结果很像jquery的深拷贝(有就替换,没有就添加) put(e.getKey(), e.getValue()); } } //移除Entry[]上e.key=key的Entry,并返回此Entry处的value public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); } //按照Key移除的业务方法 final Entry<K,V> removeEntryForKey(Object key) { //key为空hash直接给0 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; //开始循环i处的链表,先不看if语句,先理解这个循环,其实很简单,设两个指针,以e为标准,prev一直是e的 //前一个指针,循环一轮这俩指针就日后移动一格 while (e != null) { Entry<K,V> next = e.next; Object k; //找到对应的值 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { //修改次数+1 modCount++; //数量-1 size--; //若是e==prev(这种状况只会是删除i处的链表的第一个值),就把链表上的第二个值放到第一个上 if (prev == e) table[i] = next; else //不然的话,就把prev指向下一个数据的指针移到第三个值身上(跳过第二个值e) prev.next = next; e.recordRemoval(this); //返回这个Entry return e; } 向后移动指针 prev = e; e = next; } return e; } //同上,只不过此时传入的是Object对象,还要判断一下,若是此对象不是Entry格式的,就返回空 final Entry<K,V> removeMapping(Object o) { if (!(o instanceof Map.Entry)) return null; Map.Entry<K,V> entry = (Map.Entry<K,V>) o; Object key = entry.getKey(); 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; e.recordRemoval(this); return e; } 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; } //找找是不有这个value这个值 public boolean containsValue(Object value) { //等于空时特殊处理 if (value == null) return containsNullValue(); //遍历数组的每一个值 Entry[] tab = table; for (int i = 0; i < tab.length ; i++) //遍历每一个链表上的每一个值 for (Entry e = tab[i] ; e != null ; e = e.next) if (value.equals(e.value)) return true; return false; } //跟上面同样,只不过专门找寻value为空的value,而后返回boolen值 private boolean containsNullValue() { Entry[] tab = table; for (int i = 0; i < tab.length ; i++) for (Entry e = tab[i] ; e != null ; e = e.next) if (e.value == null) return true; return false; } //返回一个hashmap对象,这个对象自己是新的,内部的Entry[]数组也是新的,可是,key和value是引用过来的 //实际上,putAllForCreate(this)这个方法也是引用各变量的地址,内部属性并无在堆内存中开辟新的空间 public Object clone() { HashMap<K,V> result = null; try { //在内存中开辟空间,用于存放一个新的hashmap result = (HashMap<K,V>)super.clone(); } catch (CloneNotSupportedException e) { } //初始化长度等各类属性 result.table = new Entry[table.length]; result.entrySet = null; result.modCount = 0; result.size = 0; result.init(); //this指当前的Hashmap,就是旧的hashmap,此方法上面有注释,只是把key,value,hash和i存入新的hashmap内 result.putAllForCreate(this); return result; } //这就是Entry的真面目,内部类,也叫桶,我以为叫链条更有意思 - -|| 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; } //没啥说的 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; } //自定义equels方法 public final boolean equals(Object o) { //判断类型 if (!(o instanceof Map.Entry)) return false; //强转一个 Map.Entry e = (Map.Entry)o; //当前key Object k1 = getKey(); //传入的key Object k2 = e.getKey(); //判断key和value是否相同,此处要求内存地址或者内容相同 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; } //重写hashcode方法,为了equals准备 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<K,V> m) { } void recordRemoval(HashMap<K,V> m) { } } //建立新的桶 void addEntry(int hash, K key, V value, int bucketIndex) { //原来bucketIndex处的链表存盘 Entry<K,V> e = table[bucketIndex]; //建立新的桶,而后把以前的链表链接到新的桶上,造成新的链表 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //数据量超过阈值以后就扩大table.length,而后要从新计算阈值,老规矩仍是大于等于2 * table.length的第 //一个2的n次幂*3/4 if (size++ >= threshold) 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++; } //实现迭代器 private abstract class HashIterator<E> implements Iterator<E> { Entry<K,V> next; //下一个值 int expectedModCount; // 用来存储改变的次数 int index; //当前指针 Entry<K,V> current; //当前值 //构造方法 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(); //next赋给一个新的桶(next在构造器里被赋值过) Entry<K,V> e = next; if (e == null) throw new NoSuchElementException(); //next的指针日后移一个单位,并判断这个链表是否到最后一个值 if ((next = e.next) == null) { //若是是最后一个值,则index指向下一个数组的位置,next则指向下一个数组的第一个桶 Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } //e赋给当前值 current = e; //返回当前值 return e; } //移除当前值 public void remove() { if (current == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); Object k = current.key; current = null; HashMap.this.removeEntryForKey(k); expectedModCount = modCount; } } //把以上的类当父类继承,next()只返回value private final class ValueIterator extends HashIterator<V> { public V next() { return nextEntry().value; } } //一样继承,可是只返回桶的key private final class KeyIterator extends HashIterator<K> { public K next() { return nextEntry().getKey(); } } //返回桶 private final class EntryIterator extends HashIterator<Map.Entry<K,V>> { public Map.Entry<K,V> next() { return nextEntry(); } } //没加访问权限符,默认是friendly,只有同类和同包中的类才能访问 Iterator<K> newKeyIterator() { return new KeyIterator(); } Iterator<V> newValueIterator() { return new ValueIterator(); } Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); } //生命一个Set private transient Set<Map.Entry<K,V>> entrySet = null; //赋值ks一个new KeySet() public Set<K> keySet() { Set<K> ks = keySet; return (ks != null ? ks : (keySet = new KeySet())); } //继承抽象Set,一个Set的视图 private final class KeySet extends AbstractSet<K> { //实现接口的方法,返回以前写好的方法,返回桶的key public Iterator<K> iterator() { return newKeyIterator(); } //下面全是重写 public int size() { return size; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { return HashMap.this.removeEntryForKey(o) != null; } public void clear() { HashMap.this.clear(); } } //把桶的value转化成为Collection类型,返回Collection类型的视图 public Collection<V> values() { Collection<V> vs = values; return (vs != null ? vs : (values = new Values())); } //定义一个类,实现AbstractCollection接口,至关于建立一个AbstractCollection类型的类 private final class Values extends AbstractCollection<V> { public Iterator<V> iterator() { return newValueIterator(); } public int size() { return size; } public boolean contains(Object o) { return containsValue(o); } public void clear() { HashMap.this.clear(); } } //返回一个entrySet public Set<Map.Entry<K,V>> entrySet() { return entrySet0(); } //entrySet的视图 private Set<Map.Entry<K,V>> entrySet0() { Set<Map.Entry<K,V>> es = entrySet; return es != null ? es : (entrySet = new EntrySet()); } //其实和keySet是同样的,只不过这里的迭代器中的next方法返回的是entry,keyset中的迭代器方法返回的是key private final class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return newEntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<K,V> e = (Map.Entry<K,V>) o; Entry<K,V> candidate = getEntry(e.getKey()); return candidate != null && candidate.equals(e); } public boolean remove(Object o) { return removeMapping(o) != null; } public int size() { return size; } public void clear() { HashMap.this.clear(); } } //不懂 private void writeObject(java.io.ObjectOutputStream s) throws IOException { Iterator<Map.Entry<K,V>> i = (size > 0) ? entrySet0().iterator() : null; s.defaultWriteObject(); s.writeInt(table.length); s.writeInt(size); if (i != null) { while (i.hasNext()) { Map.Entry<K,V> e = i.next(); s.writeObject(e.getKey()); s.writeObject(e.getValue()); } } } private static final long serialVersionUID = 362498820763181265L; private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); int numBuckets = s.readInt(); table = new Entry[numBuckets]; init(); int size = s.readInt(); for (int i=0; i<size; i++) { K key = (K) s.readObject(); V value = (V) s.readObject(); putForCreate(key, value); } } // These methods are used when serializing HashSets int capacity() { return table.length; } float loadFactor() { return loadFactor; } }
最后一段迭代器解释的不是很清楚,能够逆向来想,collection和set接口都有定义这些类的方法、入参和返回参数,那若是要返回这些类型的对象,就须要一个类去实现这些接口,而后被返回。而这些接口中都有定义迭代器的方法,那就须要返回一个迭代器的对象,此时就写一个HashIterator抽象类,并实现Iterator接口,但又因为需求的不一样(有些要返回value,有些要返回key,有些又要返回entry),因此就定义为抽象类,这样就不用实现Iterator下的全部方法,下面再写三个类,继承HashIterator,并实现next()方法,用来返回不一样的需求值。而后咱们在定义一个方法,用来返回刚才编写的类的对象,将此方法放入collection和set的实现类的Iterator方法中,这样就返回了相应的视图java
PS:不是太了解为何要多加一个方法去返回三个迭代器对象,目测应该是出于访问权限的关系,可能其余的类中也须要调用到这个方法,因此设置成friendly(没加访问权限符,默认为friendly)。jquery