1.AbstractCollection类

image.png

2.AbstractList类

类图:
image.png

  1. public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}
  • �AbstractList抽象类实现了很多List接口中的方法,减轻了想要实现List接口的开发人员的负担,如果开发人员想要实现List接口,那么他可以直接继承AbstractList类然后重写对应的方法就可以了。如果开发人员想要顺序访问数据(如LinkedList类),那么继承AbstractSequentialList 类比继承AbstractList要更高效
  • 如果开发人员想要实现一个不可修改的List,那么只需要继承该类,然后重写两个方法:get(int)和size()方法
  • 如果开发人员想要实现一个可修改的List,那么需要重写set()方法,如果不重写会抛出UnsupportedOperationException异常,如果size()的大小是可变的,那么开发人员还需要重写add(int, E)和 remove(int)方法
  • 该类的子类需要有2个构造方法,一个是空参,一个是参数类型为Collection的构造方法
  • 该类的子类可以不实现iterator方法,因为这个抽象类已经实现了iterator()方法

    2.1 成员变量

    该类只有一个成员变量:该List在结构上已经被修改的次数,fail-fast
    protected transient int modCount = 0;

    2.2 成员方法

    image.png

    2.2.1 子类必须实现的抽象方法介绍:

    abstract public E get(int index);

  • 抽象方法,必须重写。返回具体索引位置的元素

  • 异常:
    • IndexOutOfBoundsException :index的值 < 0或者超出了size()的大小

      2.2.2 子类如果调用必须实现的方法介绍

      public boolean add(E e)方法

  1. public boolean add(E e) {
  2. add(size(), e);
  3. return true;
  4. }
  • 在末尾添加元素,本质调用了add(int index, E element)方法,开发人员如果想要调用这个方法,就一定要重写该方法,否则会抛出UnsupportedOperationException异常

    • 该支持该操作的List可能会限制能够添加到该列表的元素类型。如一些列表不允许添加null元素,还有一些列表对元素的其他类型有限制。实现该类的子类应该在其文档中清楚地指定要添加什么元素的任何限制。
  • 调用该方法可能会产生4种异常

    • UnsupportedOperationException :如果开发人员没有重写该方法,就会抛出该异常
    • ClassCastException :if the class of the specified element prevents it from being added to this list
    • NullPointerException :如果该实现类不允许添加Null,而开发人员添加了null
    • IllegalArgumentException :if some property of this element prevents it from being added to this list

      public void add(int index, E element)方法

  1. public void add(int index, E element) {
  2. throw new UnsupportedOperationException();
  3. }
  • 在指定位置加入元素,调用该方法需要重写。
  • 5种异常
    • UnsupportedOperationException :如果开发人员没有重写该方法,就会抛出该异
    • ClassCastException :if the class of the specified element prevents it from being added to this list
    • NullPointerException :如果该实现类不允许添加Null,而开发人员添加了null
    • IllegalArgumentException :if some property of this element prevents it from being added to this list
    • IndexOutOfBoundsException :index的值 < 0或者超出了size()的大小。

      public boolean addAll(int index, Collection<? extends E> c)方法

  1. public boolean addAll(int index, Collection<? extends E> c) {
  2. rangeCheckForAdd(index);
  3. boolean modified = false;
  4. for (E e : c) {
  5. add(index++, e);
  6. modified = true;
  7. }
  8. return modified;
  9. }
  • 使用foreach来完成增加元素的操作,在循环体中调用了add(int index, E element)方法,所以想要使用该方法,需要重写add方法,否则会抛出异常。

    public E set(int index, E element)方法

  1. public E set(int index, E element) {
  2. throw new UnsupportedOperationException();
  3. }
  • 在指定位置修改。如果调用该方法需要重写。
  • 异常:
    • UnsupportedOperationException :如果开发人员没有重写该方法,就会抛出该异常
    • ClassCastException :if the class of the specified element prevents it from being added to this list
    • NullPointerException :如果该实现类不允许添加Null,而开发人员添加了null
    • IllegalArgumentException :if some property of this element prevents it from being added to this list
    • IndexOutOfBoundsException :index的值 < 0或者超出了size()的大小

      public E remove(int index)方法

  1. public E remove(int index) {
  2. throw new UnsupportedOperationException();
  3. }
  • 功能:移除index位置的元素,它后面的元素向左移动
  • 注意,如果使用Iterator遍历的时候,只能调用iterator的remove方法,否则有fail-fast问题
  • 开发人员需要自己实现该方法,否则默认抛出UnsupportedOperationException异常

    2.2.3 子类可以不用重写的其他常用方法

    public int indexOf(Object o)方法

  1. public int indexOf(Object o) {
  2. ListIterator<E> it = listIterator();
  3. if (o==null) {
  4. while (it.hasNext())
  5. if (it.next()==null)
  6. return it.previousIndex();
  7. } else {
  8. while (it.hasNext())
  9. if (o.equals(it.next()))
  10. return it.previousIndex();
  11. }
  12. return -1;
  13. }
  • 返回List中第一次出现o元素的位置,如果不存在该元素则返回-1
  • 源码思路:
    • 这里面将Null和非null通过if语句进行判断。很多源码都是通过这种方法进行判断的,但是我觉得官方文档中提供的方法更简洁,(o==null ? get(i)==null : o.equals(get(i)))。
    • 该方法是通过Iterator进行遍历的,如果找到了就返回,找不到就一直遍历直到list末尾。(ArrayList重写了该方法,没有使用迭代器)
    • 注意这里面返回的是previousIndex()。因为,没调用一次it.next()方法,迭代器的游标都会向后移动一位。

      public void clear()方法

  1. public void clear() {
  2. removeRange(0, size());
  3. }
  4. protected void removeRange(int fromIndex, int toIndex) {
  5. ListIterator<E> it = listIterator(fromIndex);
  6. for (int i=0, n=toIndex-fromIndex; i<n; i++) {
  7. it.next();
  8. it.remove();
  9. }
  10. }
  • 清除元素
  • 调用了removeRange方法,使用迭代器。ArrayList重写了该方法

    3. AbstractSequentialList

    1. public abstract class AbstractSequentialList<E> extends AbstractList<E> { }
    AbstractSequentialList 继承自 AbstractList,是 LinkedList 的父类,是 List 接口 的简化版实现。简化在 AbstractSequentialList 只支持按次序访问,而不像 AbstractList 那样支持随机访问。

    3.1 方法

截屏2021-07-05 下午4.28.06.png

3.1.1 抽象方法(子类继承必须实现)

_public abstract _ListIterator listIterator(_int _index);

3.1.2 其他方法

public E get(int index)方法

  1. public E get(int index) {
  2. try {
  3. return listIterator(index).next();
  4. } catch (NoSuchElementException exc) {
  5. throw new IndexOutOfBoundsException("Index: "+index);
  6. }
  7. }
  • 功能:返回索引值为index的集合元素
  • 调用该类的成员变量listIterator的next()方法

public E set(int index, E element)方法

  1. public E set(int index, E element) {
  2. try {
  3. ListIterator<E> e = listIterator(index);
  4. E oldVal = e.next();
  5. e.set(element);
  6. return oldVal;
  7. } catch (NoSuchElementException exc) {
  8. throw new IndexOutOfBoundsException("Index: "+index);
  9. }
  10. }
  • 功能:设置索引值为index的集合元素的值为element
  • 源码思路:利用迭代器e来实现该功能,首先将迭代器游标放置在index位置;然后获取该位置的元素,通过调用迭代器的set方法来重新设置元素的值;最后返回index位置更改之前元素的值。

    public void add(int index, E element)方法

  1. public void add(int index, E element) {
  2. try {
  3. listIterator(index).add(element);
  4. } catch (NoSuchElementException exc) {
  5. throw new IndexOutOfBoundsException("Index: "+index);
  6. }
  7. }
  • 功能:在index位置增加一个元素,元素的值为element
  • 源码思路:使用ListIterator类型的迭代器的add()方法添加元素

    public E remove(int index)方法

  1. public E remove(int index) {
  2. try {
  3. ListIterator<E> e = listIterator(index);
  4. E outCast = e.next();
  5. e.remove();
  6. return outCast;
  7. } catch (NoSuchElementException exc) {
  8. throw new IndexOutOfBoundsException("Index: "+index);
  9. }
  10. }
  • 功能:移除下标为index的元素
  • 源码思路:使用ListIterator类型的迭代器,现将迭代器的游标置于index位置;然后定义一个E类型的变量outCast,将迭代器的下一个位置的元素赋值给outCast变量;使用迭代器的remove方法将元素移除;最后返回删除的元素。

    public boolean addAll(int index, Collection<? extends E> c)方法

  1. public boolean addAll(int index, Collection<? extends E> c) {
  2. try {
  3. boolean modified = false;
  4. ListIterator<E> e1 = listIterator(index);
  5. Iterator<? extends E> e2 = c.iterator();
  6. while (e2.hasNext()) {
  7. e1.add(e2.next());
  8. modified = true;
  9. }
  10. return modified;
  11. } catch (NoSuchElementException exc) {
  12. throw new IndexOutOfBoundsException("Index: "+index);
  13. }
  14. }
  • 功能:将集合c中的所有元素添加到当前集合的index位置,如list1中有元素[1,2,29],list2中有元素[-11,-10],在执行list1.addAll(1, list2);后,list1中的元素变为[1, -11, -10, 2, 29]
  • 源码思路:现有集合和将要添加元素的集合都要使用迭代器来实现该功能。第一步:得到当前集合的迭代器,且迭代器的游标置于index位置,得到添加元素集合的迭代器。第二步:使用while循环,利用迭代器将元素遍历出来,并添加到对应的位置。第三步:返回添加是否成功的结果

    public Iterator iterator()方法

  1. public Iterator<E> iterator() {
  2. return listIterator();
  3. }
  • 功能:返回该集合的迭代器
  • 源码思路:实现该方法是通过调用AbstractSequentialList类的抽象方法public abstract ListIterator listIterator(int index);实现的,因为不同的子类对于迭代器的处理方式是不同的,因此只能依靠子类来实现该抽象方法。

    4. AbstractSet

    1. public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {}

    是HashSet的父类,本类重写了一个AbstractCollection类的方法实现,增加了对于equals和hashCode的实现

    4.1 方法

    4.1.1 继承于Object类的方法

    equals方法:比较set与参数Object是否相等

  • 参数类型是Set,且两个Set具有相同长度,并且参数set的每个元素都存在于原set中,才会返回true。

  • 同一个对象,返回true

    1. public boolean equals(Object o) {
    2. if (o == this)
    3. return true;
    4. if (!(o instanceof Set))
    5. return false;
    6. Collection<?> c = (Collection<?>) o;
    7. if (c.size() != size())
    8. return false;
    9. try {
    10. return containsAll(c);
    11. } catch (ClassCastException unused) {
    12. return false;
    13. } catch (NullPointerException unused) {
    14. return false;
    15. }
    16. }

    hashCode() 返回set的哈希值。

  • set的哈希值是set中所有元素哈希值的总和,确保了对任意两个set:s1和s2,s1.equals(s2)就意味着s1.hashCode()==s2.hashCode()

    1. public int hashCode() {
    2. int h = 0;
    3. Iterator<E> i = iterator();
    4. // 同过迭代器遍历,累计所有的元素的哈希值
    5. while (i.hasNext()) {
    6. E obj = i.next();
    7. if (obj != null)
    8. h += obj.hashCode();
    9. }
    10. return h;
    11. }

    4.1.2 继承于AbstractCollection类

    removeAll方法,从set中将参数集合c中的所有元素删除

  • 首先判断set和参数集合谁的长度更大,如果set大,就用迭代器遍历集合,从set中删除集合中的元素;如果集合更大,就用迭代器遍历set,从中删除元素

    1. public boolean removeAll(Collection<?> c) {
    2. Objects.requireNonNull(c);
    3. boolean modified = false;
    4. if (size() > c.size()) {
    5. // 如果set大,就用迭代器遍历集合c
    6. for (Iterator<?> i = c.iterator(); i.hasNext(); )
    7. modified |= remove(i.next());
    8. } else {
    9. // 如果集合c大,就遍历set
    10. for (Iterator<?> i = iterator(); i.hasNext(); ) {
    11. if (c.contains(i.next())) {
    12. i.remove();
    13. modified = true;
    14. }
    15. }
    16. }
    17. return modified;
    18. }