- 浏览: 207660 次
- 性别:
- 来自: 湖南
文章分类
最新评论
-
guanguoxiang:
博主 方便加一个QQ么 有个问题想请教您 qq:2691669 ...
android2.3 View视图框架源码分析之一:android是如何创建一个view的? -
zhouYunan2010:
吖龙Sam 写道博主,请问在ValueAnimator.add ...
Android Property Animation(属性动画)原理分析 -
吖龙Sam:
博主,请问在ValueAnimator.addUpdateLi ...
Android Property Animation(属性动画)原理分析 -
okwudebin:
...
android2.3 View视图框架源码分析之一:android是如何创建一个view的? -
田兴苗:
...
Android Property Animation(属性动画)原理分析
集合框架源码分析三(实现类篇ArrayList,LinkedList,HashMap)
一。ArrayList,可自动扩充容量的动态数组
二。LikedList(双向循环链表)
三。HashMap(数组加链表的结合体)
四。HashSet
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则抛出IllegalArgumentException throw 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倍加1 if (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则会抛出CloneNotSupportedException throw 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()); //以指定类型返回一个新数组,长度为size System.arraycopy(elementData, 0, a, 0, size); //否则把elementData中元素复制到a if (a.length > size) //如果a的长度大于size则在最后位置加一个null元素,等于的话就不用加了 a[size] = null; //这对了解它的实际长度很有效 return a; } // Positional Access Operations public 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 easy elementData[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位置的元素设为element size++; } /** * * 移除指定位置的元素,其后面的元素都要向左移动一个位置 * 此方法的效率较低 */ 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 work for (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 modCount System.arraycopy(a, 0, elementData, size, numNew); //从size位置开始复制a size += 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 modCount int 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); //空出来的位置填充c size += 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 work int newSize = size - (toIndex - fromIndex); while (size != newSize) //这里是为了让gc工作,不直接把size设为newSize elementData[--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 stuff int 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 stuff s.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> implements List<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会赋给前驱,而每次遍历都要修改其前驱的next Entry<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 work e.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; else nextIndex--; //元素减少。nextIndex-- lastReturned = header; //重置lastReturned expectedModCount++; } 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返回的元素之前添加e nextIndex++; //元素增加,索引增加,保证下次调用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); //新节点的前驱和后继,只有一个元素的话前驱和后继都为header newEntry.previous.next = newEntry; //新节点的前驱的后继为新节点,只包含newEntry一个元素的话修改的是头结点的next newEntry.next.previous = newEntry; //新节点的后继的前驱为新节点,只包含newEntry一个元素的话修改的是头结点的previous size++; 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 work e.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) //同ArrayList a[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 magic s.defaultReadObject(); // 读长度 int size = s.readInt(); // 初始化header header = 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.75 DEFAULT_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); //根据新容量重新计算index e.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; else prev.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; 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; } /** * 是否包含空值 */ 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,否则返回null table[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 return int expectedModCount; // For fast-fail int index; // current slot Entry<K, V> current; // current entry HashIterator() { expectedModCount = modCount; if (size > 0) { // advance to first entry Entry[] 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); //此方法会改变modCount expectedModCount = 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() method Iterator<K> newKeyIterator() { return new KeyIterator(); } Iterator<V> newValueIterator() { return new ValueIterator(); } Iterator<Map.Entry<K, V>> newEntryIterator() { return new EntryIterator(); } // Views private 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 HashSets int 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 magic s.defaultWriteObject(); //写入HashMap的容量和加载系数 s.writeInt(map.capacity()); s.writeFloat(map.loadFactor()); //写入size s.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 magic s.defaultReadObject(); //读取容量和加载因子构造HashMap int capacity = s.readInt(); float loadFactor = s.readFloat(); //判断是LinkedHashMap还是HashMap map = (((HashSet) this) instanceof LinkedHashSet ? new LinkedHashMap<E, Object>( capacity, loadFactor) : new HashMap<E, Object>(capacity, loadFactor)); // 读size int size = s.readInt(); //依次读出所有元素 for (int i = 0; i < size; i++) { E e = (E) s.readObject(); map.put(e, PRESENT); } } }
评论
1 楼
minixalpha
2014-05-18
我发现一个问题,ArrayList和LinkedList在writeObject函数中有一个不一样的地方,前者对modCount进行了检查,后者没有,有什么特别的考虑吗?
相关推荐
常见的实现类有`ArrayList`、`LinkedList`、`HashSet`、`LinkedHashSet`、`HashMap`等。 2. **源码分析:ArrayList** `ArrayList`是基于动态数组实现的列表,其内部维护了一个Object类型的数组。当我们添加元素时...
`ArrayList` 是 Java 中的一种动态数组实现方式,它允许在运行时调整其大小。`ArrayList` 实现了 `List` 接口,并且内部通过一个数组来存储数据。当添加元素导致数组空间不足时,`ArrayList` 会创建一个新的更大的...
在Java编程语言中,ArrayList、LinkedList、HashMap和HashSet是四个非常重要的集合类,它们分别代表了不同类型的数据结构。这篇文章将深入探讨这些类的源码,以帮助我们更好地理解和运用它们。 首先,ArrayList是一...
在IT领域,特别是Java编程中,ArrayList和LinkedList是两种非常重要的数据结构,它们都是List接口的实现类。理解这两者的区别对于优化程序性能至关重要。面试官询问这些知识点,旨在评估应聘者的理论基础和实践能力...
- Vector 和 ArrayList 都实现了 List 接口,其中 Vector 是线程安全的,而 ArrayList 不是。ArrayList 在插入和查找性能上通常优于 Vector,因为 Vector 的同步操作会带来额外的性能开销。 - LinkedList 实现了 ...
常见的List实现类有ArrayList和LinkedList。 **ArrayList类** `ArrayList`是基于数组实现的List,它提供了一个动态增长的数组来存储元素。由于其底层是数组,所以它的随机访问(通过索引)速度非常快。但是,插入和...
掌握List集合、Set集合、Map集合的使用以及Iterator迭代器和foreach循环的使用 了解常用的集合类 熟悉泛型的使用
Java集合框架源码分析 Java集合框架是Java语言中一个非常重要的组件,提供了多种数据结构和算法来存储和操作数据。在Java集合框架中,LinkedList、ArrayList、HashMap、TreeMap等都是非常常用的数据结构。本文将对...
今天,我们将介绍 Java 集合系列中的三个重要成员:LinkedHashMap、LinkedList 和 ArrayList。 LinkedHashMap LinkedHashMap 是 Java 集合系列中的一种哈希表实现,继承自 HashMap。它的主要特点是可以维护元素的...
这篇学习笔记将深入探讨Java集合框架的基础概念、主要类库以及常见应用场景。 首先,Java集合框架分为两种基本类型:List(列表)和Set(集)。List接口代表有序的集合,允许重复元素,如ArrayList和LinkedList;而...
ArrayList、LinkedList 是 List 接口的两个主要实现类。 * Set:Set 接口继承自 Collection 接口,用于存储无序的、不可重复的元素。HashSet、LinkedHashSet 是 Set 接口的两个主要实现类。 * Map:Map 接口定义了...
List接口有三种重要的实现类:ArrayList、LinkedList和Vector。ArrayList基于数组实现,它提供了动态数组的功能,具有高效的随机访问速度,但是它的插入和删除操作相对较慢。LinkedList基于双向链表实现,它具有高效...
在Java中,集合框架主要包括接口(如List、Set、Queue)和实现这些接口的类(如ArrayList、HashSet、LinkedList等)。这个框架允许我们高效地处理各种数据结构,而无需从头开始编写代码。泛型则是Java 5引入的一项...
Java 集合框架中的实现类包括: * Set:HashSet、LinkedHashSet、TreeSet * List:ArrayList、LinkedList * Map:HashMap、TreeMap ArrayList 是一个可以自动增长容量的数组,我们可以将其看作是一个可以自动增长...
这个框架包括了多种类型的集合,如List、Set、Queue和Map,以及它们的各种实现类,如ArrayList、LinkedList、HashSet、HashMap等。下面将详细讲解这些集合及其源代码实现。 首先,`List`接口代表了一个有序的集合,...
ArrayList和LinkedList是List的两个实现类,HashMap是Map的实现类。 集合的特点 Java集合框架的集合有以下特点: * 可以存储大量数据 * 可以动态改变大小 * 提供了多种集合操作 ArrayList的使用 ArrayList是...
List有三个主要的实现类:ArrayList、LinkedList和Vector。ArrayList基于动态数组实现,适合随机访问元素;LinkedList基于链表实现,适合频繁的插入和删除操作;Vector是线程安全的,但在非多线程环境中效率比...
集合框架是一个统一的数据结构模型,它定义了一系列接口,如Collection、List、Set和Map,以及它们的实现类,如ArrayList、LinkedList、HashSet、HashMap等。容器是这些接口和类的统称,它们用于存储和管理对象。...
本文将深入探讨集合框架的总结,重点关注其核心接口、类以及如何通过源码理解和利用这些工具。 首先,集合框架的基石是接口,主要包括`List`、`Set`和`Map`。`List`接口代表有序的集合,元素可以重复,如`ArrayList...
集合框架包括接口(如List、Set、Queue)和实现这些接口的具体类(如ArrayList、LinkedList、HashSet、HashMap等)。在这个会员管理系统中,可能使用ArrayList来存储会员信息,因为它的动态增长特性和随机访问效率高...