常用集合ArrayList,LinkedList,HashMap,HashSet源码分析

来源:互联网 发布:怎么设计一个软件 编辑:程序博客网 时间:2024/05/29 12:53

一。ArrayList,可自动扩充容量的动态数组 

public class ArrayList<E> extends AbstractList<E> implements List<E>,RandomAccess, Cloneable, java.io.Serializable {private static final long serialVersionUID = 8683452581122892189L;/** *  * 所有ArrayList的元素都存储在此对象数组当中 * ArrayList的容量就是此数组的长度 */private transient Object[] elementData;/** * 实际拥有的元素的数量 *  * @serial */private int size;/** * 构造方法一,指定elementData数组初始长度 */public ArrayList(int initialCapacity) {super();if (initialCapacity < 0)//小于0则抛出IllegalArgumentExceptionthrow new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);this.elementData = new Object[initialCapacity];}/** * 构造方法二,默认elementData数组初始长度为10 */public ArrayList() {this(10);}/** * 构造方法三,构造一个包含指定 collection 的元素的List */public ArrayList(Collection<? extends E> c) {elementData = c.toArray();//toArray方法由AbstractCollection实现,返回一个对象数组size = elementData.length;      //元素的顺序是由迭代器迭代顺序决定的,详情见toArray方法实现// c.toArray might (incorrectly) not return Object[] (see 6260652)if (elementData.getClass() != Object[].class)//如果返回的不是一个数组对象elementData = Arrays.copyOf(elementData, size, Object[].class);}/** * 修剪ArrayList的容量为实际size长度 */public void trimToSize() {modCount++;//此方法改变了数组结构,需要检测是否同步int oldCapacity = elementData.length;if (size < oldCapacity) {elementData = Arrays.copyOf(elementData, size);}}/** *  * 扩充数组容量,并指定其最小的容量,即至少容量大小为minCapacity */public void ensureCapacity(int minCapacity) {modCount++;int oldCapacity = elementData.length;if (minCapacity > oldCapacity) {//指定最小容量比原来容量大才扩充Object oldData[] = elementData;int newCapacity = (oldCapacity * 3) / 2 + 1;//扩充原容量的1.5倍加1if (newCapacity < minCapacity)//扩充后还是小于要求的最小容量,则扩充容量为最小容量newCapacity = minCapacity;elementData = Arrays.copyOf(elementData, newCapacity);}}/** * 返回List中的元素个数 */public int size() {return size;}/** * List是否不含元素 */public boolean isEmpty() {return size == 0;}/** * 查看o是否包含在ArrayList中,内部调用了indexOf方法实现 */public boolean contains(Object o) {return indexOf(o) >= 0;}/** * 父类AbstractList的indexOf方法使用的是list迭代器遍历元素 * 这里重写了indexOf方法直接遍历数组即可 * 返回指定元素第一次在数组中出现的索引 * 如果找不到此元素则返回-1 */public int indexOf(Object o) {if (o == null) {for (int i = 0; i < size; i++)if (elementData[i] == null)return i;} else {for (int i = 0; i < size; i++)if (o.equals(elementData[i]))return i;}return -1;}/** * 基本同上 */public int lastIndexOf(Object o) {if (o == null) {for (int i = size - 1; i >= 0; i--)if (elementData[i] == null)return i;} else {for (int i = size - 1; i >= 0; i--)if (o.equals(elementData[i]))return i;}return -1;}/** *  * 返回ArrayList的浅拷贝实例对象,包含所有元素 */public Object clone() {try {ArrayList<E> v = (ArrayList<E>) super.clone();v.elementData = Arrays.copyOf(elementData, size);v.modCount = 0;return v;} catch (CloneNotSupportedException e) {//如果未实现Cloneable则会抛出CloneNotSupportedExceptionthrow new InternalError();}}/** *  * 返回的对象数组是安全的,因为它是一个全新的对象 * 操作返回的数组并不会影响到ArrayList对象 * */public Object[] toArray() {return Arrays.copyOf(elementData, size);}/** * 返回一个指定类型的包含List所有元素的数组 */public <T> T[] toArray(T[] a) {if (a.length < size)//如果a的长度小于List元素个数return (T[]) Arrays.copyOf(elementData, size, a.getClass());//以指定类型返回一个新数组,长度为sizeSystem.arraycopy(elementData, 0, a, 0, size);//否则把elementData中元素复制到aif (a.length > size)//如果a的长度大于size则在最后位置加一个null元素,等于的话就不用加了a[size] = null;//这对了解它的实际长度很有效return a;}// Positional Access Operationspublic E get(int index) {RangeCheck(index);//检查是否越界return (E) elementData[index];//直接返回数组某位置的元素即可}/** * 对数组指定所有的值进行替换,并返回上一个值 */public E set(int index, E element) {RangeCheck(index);//检查是否越界E oldValue = (E) elementData[index];//so easyelementData[index] = element;return oldValue;}/** * 在数组size位置添加一个元素 *  */public boolean add(E e) {ensureCapacity(size + 1); // modCount++,并检查是否需要扩充容量elementData[size++] = e;//size++return true;}/** *  * 在指定位置添加一个元素,当前在此位置的元素以及其后面的元素都要向后移动一个位置 * 此方法的效率较低 * */public void add(int index, E element) {if (index > size || index < 0)//检查是否越界throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ size);ensureCapacity(size + 1); // Increments modCount!!System.arraycopy(elementData, index, elementData, index + 1, size- index);//把原来index位置的元素,复制到index+1的位置,后面的size-index-1长度的元素依次复制elementData[index] = element;//空出的index位置的元素设为elementsize++;}/** *  * 移除指定位置的元素,其后面的元素都要向左移动一个位置 * 此方法的效率较低 */public E remove(int index) {RangeCheck(index);modCount++;//modCount是为了检测是否发生了并发操作,详细见AbstractList类E oldValue = (E) elementData[index];int numMoved = size - index - 1;//与add相比少移一个元素if (numMoved > 0)//是否移除的是最后一个元素System.arraycopy(elementData, index + 1, elementData, index,numMoved);//index位置的元素被移除了,原来index+1位置的元素复制到index位置,随后的元素依次复制elementData[--size] = null; // Let gc do its work,size位置的元素空出来了return oldValue;}/** *  * 如果o在List中存在,移除第一次出现在List中的o元素 * 如果o在List中不存在,不做任何操作 * */public boolean remove(Object o) {if (o == null) {for (int index = 0; index < size; index++)//直接遍历数组if (elementData[index] == null) {fastRemove(index);//快速移除此元素return true;}} else {for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {fastRemove(index);return true;}}return false;}/* *  * 与remove(int index)方法差不多, * 不过不用检测是否越界与返回原来的index位置的值 */private void fastRemove(int index) {modCount++;int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index + 1, elementData, index,numMoved); elementData[--size] = null; // Let gc do its work}/** * 移除所有元素,即把所有元素设为null,size=0 */public void clear() {modCount++;// Let gc do its workfor (int i = 0; i < size; i++)elementData[i] = null;size = 0;}/** * 把a中所有元素添加到数组尾部 */public boolean addAll(Collection<? extends E> c) {Object[] a = c.toArray();int numNew = a.length;ensureCapacity(size + numNew); // Increments modCountSystem.arraycopy(a, 0, elementData, size, numNew); //从size位置开始复制asize += numNew;//size增加return numNew != 0;}/** *  * 在指定位置开始添加指定集合c中的所有元素 * 当前位置及其随后位置的元素后移 */public boolean addAll(int index, Collection<? extends E> c) {if (index > size || index < 0)//检测是否越界throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ size);Object[] a = c.toArray();int numNew = a.length;ensureCapacity(size + numNew); // Increments modCountint numMoved = size - index;//移动元素数量if (numMoved > 0)System.arraycopy(elementData, index, elementData, index + numNew,numMoved);//把原来index位置的元素,复制到index+numNew的位置,后面的size-index-1长度的元素依次复制System.arraycopy(a, 0, elementData, index, numNew);//空出来的位置填充csize += numNew;return numNew != 0;}/** *  * 移除所有从fromIndex(包含)到toIndex(不包含)范围内的元素, * 左移随后的元素.如果toIndex=fromIndex,此操作无影响 * */protected void removeRange(int fromIndex, int toIndex) {modCount++;int numMoved = size - toIndex;System.arraycopy(elementData, toIndex, elementData, fromIndex,numMoved);//把toIndex位置的元素复制到fromIndex,随后的元素依次复制,总共复制numMoved个元素// Let gc do its workint newSize = size - (toIndex - fromIndex);while (size != newSize)//这里是为了让gc工作,不直接把size设为newSizeelementData[--size] = null;}/** *  * 这里并没有检测index小于0的情况 * 它总是由数组自己检测,抛出的异常也不同,为ArrayIndexOutOfBoundsException */private void RangeCheck(int index) {if (index >= size)throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ size);}/** * 序列化ArrayList,保存ArrayList实例状态 * 保存的是数组长度,及其所有元素 * */private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException {// Write out element count, and any hidden stuffint expectedModCount = modCount;s.defaultWriteObject();// 写入数组长度s.writeInt(elementData.length);// 按顺序写入所有元素for (int i = 0; i < size; i++)s.writeObject(elementData[i]);if (modCount != expectedModCount) {//检测到了并发操作throw new ConcurrentModificationException();}}/** * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is, * deserialize it). */private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {// Read in size, and any hidden stuffs.defaultReadObject();// 读出数组长度int arrayLength = s.readInt();Object[] a = elementData = new Object[arrayLength];//保存// 依次读出所有元素for (int i = 0; i < size; i++)a[i] = s.readObject();}}


二。LikedList(双向循环链表) 

public class LinkedList<E> extends AbstractSequentialList<E> implementsList<E>, Deque<E>, Cloneable, java.io.Serializable {//在第一个节点之前附设的一个节点称为头结点,有元素添加会重设值//此变量在序列化时不保存private transient Entry<E> header = new Entry<E>(null, null, null);private transient int size = 0;//List存储的Entry对象个数/** * 构造方法一,空链表 */public LinkedList() {header.next = header.previous = header; //只有一个头结点的链表}/** * 构造方法二,构造含有指定集合c中所有元素的链表 * 具体见addAll方法 */public LinkedList(Collection<? extends E> c) {this();addAll(c);}/** * 获取第一个元素的值,即头结点的下一个元素的数据部分 */public E getFirst() {if (size == 0)throw new NoSuchElementException();return header.next.element;}/** * 双向循环链表,你懂得 */public E getLast() {if (size == 0)throw new NoSuchElementException();return header.previous.element;}/** * 移除第一个元素,具体见remove()方法 */public E removeFirst() {return remove(header.next);}/** * 移除最后一个元素 */public E removeLast() {return remove(header.previous);}/** *  * 在链表开始位置添加一个元素 * 详情见addBefore() */public void addFirst(E e) {addBefore(e, header.next);}/** * 在链表最后位置添加一个元素 * 详情见addBefore() */public void addLast(E e) {addBefore(e, header);}/** * 查看链表是否包含元素o * 详细见indexOf()方法 */public boolean contains(Object o) {return indexOf(o) != -1;}/** * 链表所含元素的数量 */public int size() {return size;}/** * 跟addLast()方法类似,添加成功返回true */public boolean add(E e) {addBefore(e, header);return true;}/** * 假如链表中含有一个或多个o对象,移除第一次出现的o * 如果找不到o返回false */public boolean remove(Object o) {if (o == null) {for (Entry<E> e = header.next; e != header; e = e.next) {//从第一个元素开始遍历,每一个Entry对象都包含它下一个元素的信息if (e.element == null) {remove(e);return true;}}} else {for (Entry<E> e = header.next; e != header; e = e.next) {if (o.equals(e.element)) {remove(e);return true;}}}return false;}/** *  * 把c中所有元素按顺序添加到链表尾部 */public boolean addAll(Collection<? extends E> c) {return addAll(size, c);}/** *  * 在指定位置按顺序添加c中所有元素带List中 *  */public boolean addAll(int index, Collection<? extends E> c) {if (index < 0 || index > size)//检查是否越界,=size表示添加到最后throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ size);Object[] a = c.toArray();int numNew = a.length;if (numNew == 0)return false;modCount++;//对链表结构产生 影响的操作modCount都要加1,通过modCount可以检查是否对链表进行了并发操作Entry<E> successor = (index == size ? header : entry(index));Entry<E> predecessor = successor.previous;for (int i = 0; i < numNew; i++) {//这里不难,画一个图就出来了,主要是初始化c和修改指针//暂时使其next为successor,因为e会赋给前驱,而每次遍历都要修改其前驱的nextEntry<E> e = new Entry<E>((E) a[i], successor, predecessor);//把c中元素依次存入Entry,设置其前驱和后继。predecessor.next = e;   //重新设置前驱的next指针predecessor = e;//让e变为前驱}successor.previous = predecessor;//successor的前驱为c中最后一个元素的引用size += numNew;//长度加return true;}/** * 移除链表中所有元素 */public void clear() {Entry<E> e = header.next;while (e != header) {//表示不是只有一个头结点的空链表Entry<E> next = e.next;e.next = e.previous = null;//let gc worke.element = null;e = next;}header.next = header.previous = header;//初始头结点size = 0;modCount++;}// Positional Access Operations/** * 返回指定位置的元素时 */public E get(int index) {return entry(index).element;}/** * 设置指定位置的元素 */public E set(int index, E element) {Entry<E> e = entry(index);E oldVal = e.element;e.element = element;return oldVal;}/** *  * 把指定元素添加到指定位置,需先定位到此位置的节点 * 详情见addBefore() */public void add(int index, E element) {addBefore(element, (index == size ? header : entry(index)));}/** * 移除指定位置的元素 */public E remove(int index) {return remove(entry(index));}/** *  * 返回指定索引位置的Entry对象,需要依次遍历得到。 * 这里稍做了一下优化,如果index < size/2 从前面开始遍历 * 如果index >= size/2 从后面开始遍历 */private Entry<E> entry(int index) {if (index < 0 || index >= size)//index在0(包含)到size(不包含)之间,索引从0开始throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ size);Entry<E> e = header;if (index < (size >> 1)) {for (int i = 0; i <= index; i++)e = e.next;//依次调用e.next才能得到,需调用index+1次,因为它是从头结点开始的} else {for (int i = size; i > index; i--)e = e.previous; //依次调用e.previous才能得到}return e;}// Search Operations/** *  * 返回o第一次出现的位置,如果在List中找不到o返回-1 */public int indexOf(Object o) {int index = 0;//链表的索引也是从0开始if (o == null) {for (Entry e = header.next; e != header; e = e.next) {//从头结点开始,依次遍历if (e.element == null)return index;index++;}} else {for (Entry e = header.next; e != header; e = e.next) {if (o.equals(e.element))return index;index++;}}return -1;}/** * 双向循环链表,从后面开始遍历即可 */public int lastIndexOf(Object o) {int index = size;if (o == null) {for (Entry e = header.previous; e != header; e = e.previous) {index--;if (e.element == null)return index;}} else {for (Entry e = header.previous; e != header; e = e.previous) {index--;if (o.equals(e.element))return index;}}return -1;}// Queue operations.有关队列的基本操作/** * 如果链表长度不为空,获取第一个元素 * 否则返回null */public E peek() {if (size == 0)return null;return getFirst();}/** * 跟peek方法相似,不过这里size为0的话直接抛出异常 */public E element() {return getFirst();}/** * 如果链表长度不为空,移除第一个元素,并返回它 * 否则返回null */public E poll() {if (size == 0)return null;return removeFirst();}/** * 与poll方法类似,不过长度为空,即header.next = header * 抛出NoSuchElementException */public E remove() {return removeFirst();}/** * 添加一个元素到链表尾部 */public boolean offer(E e) {return add(e);}// Deque operations/** * 添加一个元素到头结点之后,原来的第一个节点之前 */public boolean offerFirst(E e) {addFirst(e);return true;}/** * 在尾部添加一个元素 */public boolean offerLast(E e) {addLast(e);return true;}/** * 获取第一个元素,如果size为0,返回空 * 否则返回第一个元素 */public E peekFirst() {if (size == 0)return null;return getFirst();}/** * 获取最后一个元素,如果size为0,返回空 * 否则返回最后一个元素 */public E peekLast() {if (size == 0)return null;return getLast();}/** *  * 移除第一个元素并返回它 * 如果size为0则直接返回null */public E pollFirst() {if (size == 0)return null;return removeFirst();}/** * 移除最后一个元素并返回它 * 如果size为0则直接返回null */public E pollLast() {if (size == 0)return null;return removeLast();}/** * 在开始位置添加一个元素 */public void push(E e) {addFirst(e);}/** * 移除第一个元素 */public E pop() {return removeFirst();}/** *  * 移除第一次出现的指定的元素 * 如果遍历整个List后没有找到o,则不做任何改变 *  */public boolean removeFirstOccurrence(Object o) {return remove(o);}/** * 这个差不多,从后面开始遍历即可 */public boolean removeLastOccurrence(Object o) {if (o == null) {for (Entry<E> e = header.previous; e != header; e = e.previous) {if (e.element == null) {remove(e);return true;}}} else {for (Entry<E> e = header.previous; e != header; e = e.previous) {if (o.equals(e.element)) {remove(e);return true;}}}return false;}/** *  * 返回一个list-iterator. */public ListIterator<E> listIterator(int index) {return new ListItr(index);}/** * 重新 实现ListIterator,使其跟符合链表的特性 * iterator方法由AbstractSequentialList实现了, * 但是调用的还是本ListIterator。只不过只能使用iterator接口的方法 * */private class ListItr implements ListIterator<E> {private Entry<E> lastReturned = header;//上一次调用next或previous返回的元素,没有调用next则为头结点private Entry<E> next;//下一次调用next方法返回的元素private int nextIndex;//下一次调用next返回的元素的索引private int expectedModCount = modCount;//用来检测遍历过程中是否产生了并发操作ListItr(int index) {//构造器,是迭代器定位到index位置,要返回index位置的元素需调用一次next()方法时if (index < 0 || index > size)throw new IndexOutOfBoundsException("Index: " + index+ ", Size: " + size);if (index < (size >> 1)) {//从前面开始遍历next = header.next; //这是index为0的元素for (nextIndex = 0; nextIndex < index; nextIndex++)next = next.next;//最终next为第index个元素,index从0开始} else {//从后面开始遍历next = header;for (nextIndex = size; nextIndex > index; nextIndex--)next = next.previous;//最终next为第index个元素,index从0开始}}public boolean hasNext() {//size位置可没有元素return nextIndex != size;}public E next() {checkForComodification();if (nextIndex == size)throw new NoSuchElementException();lastReturned = next;next = next.next;//这里与ArrayList中的cursor何其相似nextIndex++;return lastReturned.element;}public boolean hasPrevious() {return nextIndex != 0;}public E previous() {if (nextIndex == 0)throw new NoSuchElementException();lastReturned = next = next.previous;nextIndex--;checkForComodification();return lastReturned.element;}public int nextIndex() {//返回下一次调用next返回的元素的索引return nextIndex;}public int previousIndex() {//返回下一次调用previous返回的元素的索引return nextIndex - 1;}public void remove() {checkForComodification();Entry<E> lastNext = lastReturned.next;try {LinkedList.this.remove(lastReturned);//移除上一层调用next()或previous返回的元素} catch (NoSuchElementException e) {throw new IllegalStateException();}if (next == lastReturned)//表明是调用previous后才调用remove方法next = lastNext;elsenextIndex--;//元素减少。nextIndex--lastReturned = header;//重置lastReturnedexpectedModCount++;}public void set(E e) {if (lastReturned == header)throw new IllegalStateException();checkForComodification();lastReturned.element = e;}public void add(E e) {checkForComodification();lastReturned = header;addBefore(e, next);//在上一次调用next返回的元素之后,在上次调用previous返回的元素之前添加enextIndex++;//元素增加,索引增加,保证下次调用next()不是返回添加的元素expectedModCount++;}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}/** * LinkedList的元素节点,保存当前节点的元素 * 以及下一个节点,和上一个节点的引用 * 由此看出LinkedList是一个双向链表 */private static class Entry<E> {E element;//当前节点元素Entry<E> next;//下一个节点引用Entry<E> previous;//上一个节点引用Entry(E element, Entry<E> next, Entry<E> previous) {this.element = element;this.next = next;this.previous = previous;}}/** *  在entry之前添加一个节点e *  */private Entry<E> addBefore(E e, Entry<E> entry) {Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);//新节点的前驱和后继,只有一个元素的话前驱和后继都为headernewEntry.previous.next = newEntry;//新节点的前驱的后继为新节点,只包含newEntry一个元素的话修改的是头结点的nextnewEntry.next.previous = newEntry;//新节点的后继的前驱为新节点,只包含newEntry一个元素的话修改的是头结点的previoussize++;modCount++;return newEntry;}/** * 移除指定节点  */private E remove(Entry<E> e) {if (e == header)throw new NoSuchElementException();E result = e.element;//修改节点指针e.previous.next = e.next;//e的前驱的后继等于e的后继e.next.previous = e.previous;//e的后继的前驱等于e的前驱e.next = e.previous = null;//let gc worke.element = null;size--;//size--modCount++;return result;}/** * 逆序返回所有元素的迭代器 */public Iterator<E> descendingIterator() {return new DescendingIterator();}/** Adapter to provide descending iterators via ListItr.previous */private class DescendingIterator implements Iterator {final ListItr itr = new ListItr(size());public boolean hasNext() {return itr.hasPrevious();}public E next() {return itr.previous();}public void remove() {itr.remove();}}/** * 返回一个LikedList的浅拷贝对象 */public Object clone() {LinkedList<E> clone = null;try {clone = (LinkedList<E>) super.clone();} catch (CloneNotSupportedException e) {throw new InternalError();}// Put clone into "virgin" state,即重置其为初始状态clone.header = new Entry<E>(null, null, null);clone.header.next = clone.header.previous = clone.header;clone.size = 0;clone.modCount = 0;// 初始化克隆对象for (Entry<E> e = header.next; e != header; e = e.next)clone.add(e.element);return clone;}/** * 返回一个新建对象数组,包含链表中所有元素 */public Object[] toArray() {Object[] result = new Object[size];//新建一size长度对象数组int i = 0;for (Entry<E> e = header.next; e != header; e = e.next)//遍历赋值result[i++] = e.element;return result;}/** * 所有toArray方法都是一个思想... * 只是遍历方式不同 * */public <T> T[] toArray(T[] a) {if (a.length < size)//如果指定数组长度小于size,新建一数组a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);int i = 0;Object[] result = a;for (Entry<E> e = header.next; e != header; e = e.next)result[i++] = e.element;if (a.length > size) //同ArrayLista[size] = null;return a;}private static final long serialVersionUID = 876323262645176354L;/** * 序列化LikedList,保存其状态 */private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException {// Write out any hidden serialization magic//添加一些序列化的额外信息,表明它是一个序列化的文件s.defaultWriteObject();// 写长度s.writeInt(size);// 写元素for (Entry e = header.next; e != header; e = e.next)s.writeObject(e.element);}/** * 从流中读取 */private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {// Read in any hidden serialization magics.defaultReadObject();// 读长度int size = s.readInt();// 初始化headerheader = new Entry<E>(null, null, null);header.next = header.previous = header;// 按顺序写入所有元素for (int i = 0; i < size; i++)addBefore((E) s.readObject(), header);}}

三。HashMap(数组加链表的结合体) 

/** * 作用:用于实现快速查找 * HashMap实现的数据结构:动态数组和链表的结合体 * */public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>,Cloneable, Serializable {/** * 默认初始数组容量,必须为2的幂 */static final int DEFAULT_INITIAL_CAPACITY = 16;/** * * 最大容量为1 * 2^30 即2的30次方 */static final int MAXIMUM_CAPACITY = 1 << 30;/** *  * hashMap的加载系数,当数组中的元素增多时,通过hash函数算出的数组下标 * 相同几率增加。为保证查找的效率,当数组中的元素超过 * load_factor * table.length 时就要扩充容量 * 默认加载系数为0.75 */static final float DEFAULT_LOAD_FACTOR = 0.75f;/** *  * 数组存放Entry对象,单向链表的第一个元素, * 通过它可以遍历整个链表。 * table长度会在需要时进行扩充,table长度始终为2的幂 */transient Entry[] table;/** * key-value键值对个数 */transient int size;/** * HashMap size >= threshlod时就扩充数组容量 */int threshold;/** * hash表加载因子 */final float loadFactor;/** *  * hash表发生结构性改变的次数,这些方法包括,put,remove等对size进行改变的操作 * 用iterator遍历时可以用来检测是否对HashMap进行了并发操作 */transient volatile int modCount;/** * 根据指定的初始容量和加载系数构建hashMap * 初始容量如果不是2的幂,会被构造成2的幂 */public HashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: "+ initialCapacity);if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: "+ loadFactor);//找到一个2的幂的数,使其大于等于初始容量int capacity = 1;while (capacity < initialCapacity)capacity <<= 1;// capacity = capacity << 1,左移一位 this.loadFactor = loadFactor;threshold = (int) (capacity * loadFactor);table = new Entry[capacity];init();//所有构造方法都含有此空方法,做一些其他初始化操作。根据业务要求,可由其子类实现}/** * 根据指定容量与默认加载系数构建HashMap */public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);}/** * 采用默认容量16与默认加载系数0.75构建HashMap */public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR;threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);table = new Entry[DEFAULT_INITIAL_CAPACITY];init();}/** *  * 根据指定Map中的键值对,默认加载因子构建HashMap */public HashMap(Map<? extends K, ? extends V> m) {this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, //size要小于容量*0.75DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);putAllForCreate(m);}// internal utilities/** * * 在new table之后,在添加元素之前被调用 */void init() {}/** *  * hash算法,根据key的hashCode计算其hash值 * 此算法看的一知半解,大家有兴趣可以查看其它资料 * >>>无符号右移     ^按位异或 */static int hash(int h) {// This function ensures that hashCodes that differ only by// constant multiples at each bit position have a bounded// number of collisions (approximately 8 at default load factor).h ^= (h >>> 20) ^ (h >>> 12);return h ^ (h >>> 7) ^ (h >>> 4);}/** * 根据hash值与数组长度计算其数组索引。 * length为2的幂,使不同hash通过h&(length-1)产生的索引尽量不同,即减少碰撞。 * 如果产生的索引都不同,通过找到索引就可以直接找到value,而不需要遍历链表。 * 可以使产生的索引始终在table索引范围之内 * 此方法详细解析可见:http://www.iteye.com/topic/539465 */static int indexFor(int h, int length) {return h & (length - 1);}/** * 键值对数目 */public int size() {return size;}/** * 判断hashMap是否为空 */public boolean isEmpty() {return size == 0;}/** *  * 通过key值获得value,如果没有找到此key则返回null。 * 不过返回null也可能是其value为null * 通过contain方法可判断Map中是否含有此键 *  */public V get(Object key) {if (key == null)//空键另外处理return getForNullKey();int hash = hash(key.hashCode());//定位到index,并查看e的下一个节点是否为null,否则继续遍历for (Entry<K, V> e = 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;}/** *  * 空键的hash值为0,所以其数组中的索引为0. * 独立把此方法分离出来是为了提高两个最常用的方法get和put的性能, * 但在其它情况下此方法被合并了. */private V getForNullKey() {for (Entry<K, V> e = table[0]; e != null; e = e.next) {if (e.key == null)return e.value;}return null;}/** * 如果Map中含有此key返回true. * 具体见getEntry. */public boolean containsKey(Object key) {return getEntry(key) != null;}/** *  * 通过返回Entry而不是value可确保Map中是否含有此key */final Entry<K, V> getEntry(Object key) {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;if (e.hash == hash&& ((k = e.key) == key || (key != null && key.equals(k))))return e;}return null;}/** *  * replaced. * 通过指定的key值存储指定value,如果Map中含有此key则用指定value替换old value */public V put(K key, V value) {if (key == null)return putForNullKey(value);int hash = hash(key.hashCode());int i = indexFor(hash, table.length);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);//当你调用put并在替换老值时会调用此方法,假如你在这个时候想做一些额外操作可继承Entry重写此方法return oldValue;}}modCount++;addEntry(hash, key, value, i);return null;}private V putForNullKey(V value) {for (Entry<K, V> e = table[0]; e != null; e = e.next) {if (e.key == null) {//如果含有此null key替换老值V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(0, null, value, 0);//否则添加此Entry到数组return null;}/** *  * 此方法用来替代put方法,不会调整table大小。 * 此方法在确认map键值对个数始终小于table.length * load_factor, * 添加元素时调用。主要是为了提高性能 */private void putForCreate(K key, V value) {int hash = (key == null) ? 0 : hash(key.hashCode());int i = indexFor(hash, table.length);/** *  * 查看是否存在同样的key值,如果有就替换其value */for (Entry<K, V> e = table[i]; e != null; e = e.next) {Object k;if (e.hash == hash&& ((k = e.key) == key || (key != null && key.equals(k)))) {e.value = value;return;}}//否则添加一个Entry对象createEntry(hash, key, value, i);}/** * 依次遍历添加 * */private void putAllForCreate(Map<? extends K, ? extends V> 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());}}/** *  * 当HashMap中元素越来越多时,发生碰撞的几率增大,为提高效率,当元素超过 * threshold时就要对数组进行扩充,扩充后,原数组中所有数据都要重新计算 * 其在新数组中的位置,所以每扩充一次对性能影响是非常大的。 */void resize(int newCapacity) {Entry[] oldTable = table;int oldCapacity = oldTable.length;if (oldCapacity == MAXIMUM_CAPACITY) {//如果数组容量已经最大,不再扩充。threshold = Integer.MAX_VALUE;//使threshold = Integer.MAX_VALUE,使resize方法不再被调用return;}Entry[] newTable = new Entry[newCapacity];transfer(newTable);table = newTable;threshold = (int) (newCapacity * loadFactor);}/** *  * 把table中所有的Entry对象转移到newTabel */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) {src[j] = null;//只置空第一个节点即可,因为此节点存在数组中do {Entry<K, V> next = e.next;int i = indexFor(e.hash, newCapacity);  //根据新容量重新计算indexe.next = newTable[i];//最后添加的节点放最前面newTable[i] = e;e = next;} while (e != null);}}}/** * * 把所有元素从知道map中复制到本map */public void putAll(Map<? extends K, ? extends V> m) {int numKeysToBeAdded = m.size();if (numKeysToBeAdded == 0)return;/* *  * 如果numKeysToBeAdded大于或等于threshold就扩展map * 这是一个保守的方法。本来的条件应该是(m.size() + size) >= threshold, * 但是如果所有被添加的元素的key值在本map中都存在,map扩充的容量将是 * 最佳容量的两倍。这极大的浪费了空间,所以采用此保守的方法计算newCapacity。 * 否则不再此处扩充就在put方法中进行扩充 */if (numKeysToBeAdded > threshold) {int targetCapacity = (int) (numKeysToBeAdded / loadFactor + 1);if (targetCapacity > MAXIMUM_CAPACITY)targetCapacity = MAXIMUM_CAPACITY;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 = m.entrySet().iterator(); i.hasNext();) {Map.Entry<? extends K, ? extends V> e = i.next();put(e.getKey(), e.getValue());}}/** * 根据知道key移除键值对,返回移除的元素 */public V remove(Object key) {Entry<K, V> e = removeEntryForKey(key);return (e == null ? null : e.value);}/** * 根据key移除Entry对象 */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> e = prev;while (e != null) {Entry<K, V> next = e.next;Object k;if (e.hash == hash&& ((k = e.key) == key || (key != null && key.equals(k)))) {modCount++;size--;if (prev == e)//表明链表只有一个Entry对象table[i] = next;elseprev.next = next;//修改指针e.recordRemoval(this);//在移除元素时调用return e;}prev = e;e = next;}return e;}/** * 同remove方法基本相似 */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;elseprev.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;}/** * 是否包含空值 */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的浅拷贝实例 */public Object clone() {HashMap<K, V> result = null;try {result = (HashMap<K, V>) super.clone();} catch (CloneNotSupportedException e) {// assert false;}result.table = new Entry[table.length];result.entrySet = null;result.modCount = 0;result.size = 0;result.init();result.putAllForCreate(this);//依次添加本map所有元素到浅拷贝的map实例中return result;}static class Entry<K, V> implements Map.Entry<K, V> {final K key;V value;Entry<K, V> next;final int hash;/** * Creates new entry. */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;}//Entry的equals方法,键值相等即Entry对象相等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;}/** * 重写hashCode方法,异或key与value的hashCode值 */public final int hashCode() {return (key == null ? 0 : key.hashCode())^ (value == null ? 0 : value.hashCode());}public final String toString() {return getKey() + "=" + getValue();}/** * * 当添加一键值对,发现键已存在时调用此方法 *  可以继承Entry对象重写此方法 */void recordAccess(HashMap<K, V> m) {}/** * 当有Entry对象被移除时,此方法被调用。 * 可以继承Entry对象重写此方法 */void recordRemoval(HashMap<K, V> m) {}}/** *  * 如果适当此方法会resize table */void addEntry(int hash, K key, V value, int bucketIndex) {Entry<K, V> e = table[bucketIndex]; table[bucketIndex] = new Entry<K, V>(hash, key, value, e);if (size++ >= threshold)//如果size超过threshold就调整数组容量大小为原来的两倍resize(2 * table.length);}/** * * 与addEntry方法类似。但是方法不需要担心容量的扩充 */void createEntry(int hash, K key, V value, int bucketIndex) {Entry<K, V> e = table[bucketIndex];//如果此节点已经有一个Entry对象,返回e,否则返回nulltable[bucketIndex] = new Entry<K, V>(hash, key, value, e);//以新加入的节点作为第一个节点size++;}/** * 抽象类,next方法由其子类实现, * 不同的next方法返回不同的迭代器 * 包括key,value,keySet迭代器 * */private abstract class HashIterator<E> implements Iterator<E> {Entry<K, V> next; // next entry to returnint expectedModCount; // For fast-failint index; // current slotEntry<K, V> current; // current entryHashIterator() {expectedModCount = modCount;if (size > 0) { // advance to first entryEntry[] t = table;//遍历直到获取第一个Entry对象,因为有的索引可能为空while (index < t.length && (next = t[index++]) == null) ;}}public final boolean hasNext() {return next != null;}/** * 返回下一个Entry对象 * */final Entry<K, V> nextEntry() {if (modCount != expectedModCount)throw new ConcurrentModificationException();Entry<K, V> e = next;if (e == null)throw new NoSuchElementException();if ((next = e.next) == null) {Entry[] t = table;//继续找不为空的索引中的Entry对象while (index < t.length && (next = t[index++]) == null);}current = e;return e;}/** * 移除当前Entry对象,即调用nextEntry返回的Entry对象 */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);//此方法会改变modCountexpectedModCount = modCount;//所以可以用此语句检测是否产生了并发操作}}//依次重写next方法,返回不同的迭代器。private final class ValueIterator extends HashIterator<V> {public V next() {return nextEntry().value;}}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();}}// Subclass overrides these to alter behavior of views' iterator() methodIterator<K> newKeyIterator() {return new KeyIterator();}Iterator<V> newValueIterator() {return new ValueIterator();}Iterator<Map.Entry<K, V>> newEntryIterator() {return new EntryIterator();}// Viewsprivate transient Set<Map.Entry<K, V>> entrySet = null;/** * 返回一个key集。 * 此Set集合只在第一次调用keySet()时被创建,此后返回的都是同一个Set。      * 此方法不是线程安全的,大量线程多次调用此方法返回的可能不是同一个Set(可能是重新new的)     *      * 对map的修改会反应到Set当中,相反,对Set中key进行移除操作,比如      * Iterator.remove,Set.remove ,removeAll,retainAll,clear等操作时被移除的键      * 和它相关联的值也将从map中被移除,但是此Set不支持任何添加操作  */public Set<K> keySet() {Set<K> ks = keySet;return (ks != null ? ks : (keySet = new KeySet()));}private final class KeySet extends AbstractSet<K> {public Iterator<K> iterator() {return newKeyIterator();}public int size() {return size;}public boolean contains(Object o) {return containsKey(o);}/** * 重写了Set的remove方法, * 父类remove都是调用迭代器的remove方法 * */public boolean remove(Object o) {return HashMap.this.removeEntryForKey(o) != null;}public void clear() {HashMap.this.clear();}}/** * 同上 */public Collection<V> values() {Collection<V> vs = values;return (vs != null ? vs : (values = new Values()));}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();}}/** * 同上 */public Set<Map.Entry<K, V>> entrySet() {return entrySet0();}private Set<Map.Entry<K, V>> entrySet0() {Set<Map.Entry<K, V>> es = entrySet;return es != null ? es : (entrySet = new EntrySet());}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();}}/** * 序列化hashMap对象 */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);// Write out keys and values (alternating)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;/** * 读出HashMap对象 */private void readObject(java.io.ObjectInputStream s) throws IOException,ClassNotFoundException {//读出默认信息s.defaultReadObject();// 读容量int numBuckets = s.readInt();table = new Entry[numBuckets];init(); // Give subclass a chance to do its thing.// 读长度int size = s.readInt();//读键值对,并还原HashMap元素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 HashSetsint capacity() {return table.length;}float loadFactor() {return loadFactor;}}

四。HashSet 

/** * 散列集(hashSet),就是不存在重复元素的集合。 * HashSet是在HashMap的基础上实现的, * 以HashSet的元素做Key值使其值不会重复 * */public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable,java.io.Serializable {static final long serialVersionUID = -5024744406713321676L;private transient HashMap<E, Object> map;//以Object作为虚假的Value值private static final Object PRESENT = new Object();/** *  * 构造一个新的,空Set集; * 实际是构造一个默认初始容量为16,加载因子为0.75的空HashMap */public HashSet() {map = new HashMap<E, Object>();}/** * * 构造一个包含指定集合c中所有元素的新的Set集。 * 实际是构造包含集合c中所有元素的HashMap. * 初始大小必须大于容量*0.75 *  */public HashSet(Collection<? extends E> c) {map = new HashMap<E, Object>(Math.max((int) (c.size() / .75f) + 1, 16));addAll(c);}/** * 以指定初始容量和加载因子构造HashMap */public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<E, Object>(initialCapacity, loadFactor);}/** * 以初始容量构造HashMap */public HashSet(int initialCapacity) {map = new HashMap<E, Object>(initialCapacity);}/** *  * 构造一个Linked hash set. * 以指定初始容量,加载因子构造LinkedHashMap,dummy只是为了区别其他构造方法 *  */HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<E, Object>(initialCapacity, loadFactor);}/** * 获得HashMap的键集迭代器 */public Iterator<E> iterator() {return map.keySet().iterator();}/** * 返回元素个数 */public int size() {return map.size();}/** * 判断Hash集是否为空 */public boolean isEmpty() {return map.isEmpty();}/** * 如果Map中含有此key则返回true */public boolean contains(Object o) {return map.containsKey(o);}/** *  * 如果e不存在于Set中则添加e到集合, * 如果Map中key集不存在e,则添加并返回null,否则替换原来的value,返回oldValue * */public boolean add(E e) {return map.put(e, PRESENT) == null;}/** * 移除指定元素 */public boolean remove(Object o) {return map.remove(o) == PRESENT;}/** * 清空map */public void clear() {map.clear();}/** * 返回HashSet的浅拷贝对象 */public Object clone() {try {HashSet<E> newSet = (HashSet<E>) super.clone();newSet.map = (HashMap<E, Object>) map.clone();return newSet;} catch (CloneNotSupportedException e) {throw new InternalError();}}private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException {// Write out any hidden serialization magics.defaultWriteObject();//写入HashMap的容量和加载系数s.writeInt(map.capacity());s.writeFloat(map.loadFactor());//写入sizes.writeInt(map.size());//依次写入键值for (Iterator i = map.keySet().iterator(); i.hasNext();)s.writeObject(i.next());}private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {// Read in any hidden serialization magics.defaultReadObject();//读取容量和加载因子构造HashMapint capacity = s.readInt();float loadFactor = s.readFloat();//判断是LinkedHashMap还是HashMapmap = (((HashSet) this) instanceof LinkedHashSet ? new LinkedHashMap<E, Object>(capacity, loadFactor): new HashMap<E, Object>(capacity, loadFactor));// 读sizeint size = s.readInt();//依次读出所有元素for (int i = 0; i < size; i++) {E e = (E) s.readObject();map.put(e, PRESENT);}}}



1 0