个人深入理解java集合框架:5、AbstractCollection和AbstractList

本片博文参考拭心Java 集合框架深入理解 系列
自己学习理解的一篇博文
基于jdk1.8下研究学习。

前言

本来按照计划直接跳到去写ArrayList中去,但是认为AbstractCollection和AbstractList还是需要了解一下的。

AbstractCollection

官方文档中的说明:

This class provides a skeletal implementation of the Collection interface, to minimize the effort required to implement this interface.

To implement an unmodifiable collection, the programmer needs only to extend this class and provide implementations for the iterator and size methods. (The iterator returned by the iterator method must implement hasNext and next.)

To implement a modifiable collection, the programmer must additionally override this class’s add method (which otherwise throws an UnsupportedOperationException), and the iterator returned by the iterator method must additionally implement its remove method.

The programmer should generally provide a void (no argument) and Collection constructor, as per the recommendation in the Collection interface specification.
The documentation for each non-abstract method in this class describes its implementation in detail. Each of these methods may be overridden if the collection being implemented admits a more efficient implementation.

This class is a member of the Java Collections Framework.

机器翻译一下:

此类提供了Collection接口的基本实现,以最大程度地减少实现此接口所需的工作。
要实现不可修改的集合,程序员只需扩展此类并为iterator和size方法提供实现。 (由迭代器方法返回的迭代器必须实现hasNext和next。)
要实现可修改的集合,程序员必须另外重写此类的add方法(否则将抛出UnsupportedOperationException),并且iterator方法返回的迭代器必须另外实现其remove方法。
根据Collection接口规范中的建议,程序员通常应提供一个void(无参数)和Collection构造函数。
此类中每个非抽象方法的文档都详细描述了其实现。如果正在实现的集合允许更有效的实现,则可以覆盖这些方法中的每一个。
此类是Java Collections Framework的成员。

从官方的解释中就可以知道,AbstractCollection是Collection接口的一个抽象类实现,也是一个基本的实现;

构造方法:

protected AbstractCollection() {

}

AbstractCollection的构造方法是protected,在官方建议中提供一个void(无参数)和Collection构造函数。因此在子类中最好实现自己的无参构造函数。

作为抽象类,AbstractCollection 定义了两个抽象方法。

public abstract Iterator<E> iterator();

public abstract int size();

因此只要继承了AbstractCollection的子类都必须去实现这两个方法(除非子类也是抽象类);

AbstractCollection中值得注意是:

public boolean add(E e) {
    throw new UnsupportedOperationException();
}

直接使用AbstractCollection的add()方法会报错,因此AbstractCollection是不支持添加单个对象;

其他:
在整体设计之初,AbstractCollection就是作为Collection一个基本的实现,构造一个内部数据不可改变的集,AbstractCollection有许多不是抽象的方法,因此在子类并不是需要都实现的,这也是抽象和接口的区别之一。

AbstractList

直接上官方文档的一个介绍:

This class provides a skeletal implementation of the List interface to minimize the effort required to implement this interface backed by a “random access” data store (such as an array). For sequential access data (such as a linked list), AbstractSequentialList should be used in preference to this class.
To implement an unmodifiable list, the programmer needs only to extend this class and provide implementations for the get(int) and size() methods.
To implement a modifiable list, the programmer must additionally override the set(int, E) method (which otherwise throws an UnsupportedOperationException). If the list is variable-size the programmer must additionally override the add(int, E) and remove(int) methods.
The programmer should generally provide a void (no argument) and collection constructor, as per the recommendation in the Collection interface specification.
Unlike the other abstract collection implementations, the programmer does not have to provide an iterator implementation; the iterator and list iterator are implemented by this class, on top of the “random access” methods: get(int), set(int, E), add(int, E) and remove(int).
The documentation for each non-abstract method in this class describes its implementation in detail. Each of these methods may be overridden if the collection being implemented admits a more efficient implementation.
This class is a member of the Java Collections Framework.
机器翻译一下:
此类提供了List接口的基本实现,以最大程度地减少实现由“随机访问”数据存储(例如数组)支持的该接口所需的工作。对于顺序访问数据(例如链表),应优先使用AbstractSequentialList代替此类。
要实现不可修改的列表,程序员仅需要扩展此类并为get(int)和size()方法提供实现。
要实现可修改的列表,程序员必须另外重写set(int,E)方法(否则将抛出UnsupportedOperationException)。如果列表是可变大小的,则程序员必须另外重写add(int,E)和remove(int)方法。
程序员通常应按照Collection接口规范中的建议提供一个void(无参数)和collection构造函数。
与其他抽象集合实现不同,程序员不必提供迭代器实现。迭代器和列表迭代器由此类在“随机访问”方法之上实现:get(int),set(int,E),add(int,E)和remove(int)。
此类中每个非抽象方法的文档都详细描述了其实现。如果正在实现的集合允许更有效的实现,则可以覆盖这些方法中的每一个。
此类是Java Collections Framework的成员。

从官方文档,我们可以得出,AbstractList是一个基本的List实现,基本上就是定义了一个框架;

为什么说只是定义一个框架?

我们来看看AbstractList实现的一些方法:

public E set(int index, E element) {
    throw new UnsupportedOperationException();
}
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}
public E remove(int index) {
    throw new UnsupportedOperationException();
}

继承了AbstractCollection同时自身并没有实现可修改的方法,因此AbstractList也是一个不可改的集。
AbstractList定义了许多的操作,但是并没有定义数据集的增删改操作方法,因此我们可以定义为这是一个框架一样,是List的一个基本的实现。

那为什么设定为抽象?

试想在一个架构中,如果AbstractList不是抽象的,那么其子类是否去实现他的规定的方式呢?
抽象本身有一点重要的意义就是抽象类的抽象方法,子类必须去重写。架构设计者也是在这一点上,抽离了部分的方法,使子类必须去实现。
AbstractList中设置的许多方法都是直接报UnsupportedOperationException这个错误的,因此它的子类都应主动重写此方法。
关于为什么不直接将这类设置报错的方法设置为抽象方法,因为并非所有子类都需要这类方法。
AbstractList继承了AbstractCollection抽象类同时也实现了List接口,在已知的子类中有:AbstractSequentialList , ArrayList , Vector;
定义了一个抽象方法:

abstract public E get(int index);
实现的部分方法

接下来,我们来看看AbstractList的部分实现方法:

  • 关于位置、元素的操作;
// 查找到元素首次出现的索引位置,无则返回-1
public int indexOf(Object o) {
    ListIterator<E> it = listIterator();
    if (o==null) {
        while (it.hasNext())
            if (it.next()==null)
                return it.previousIndex();
    } else {
        while (it.hasNext())
            if (o.equals(it.next()))
                return it.previousIndex();
    }
    return -1;
}

// 查找到元素最后一次出现到的位置,无则返回-1
public int lastIndexOf(Object o) {
    ListIterator<E> it = listIterator(size());
    if (o==null) {
        while (it.hasPrevious())
            if (it.previous()==null)
                return it.nextIndex();
    } else {
        while (it.hasPrevious())
            if (o.equals(it.previous()))
                return it.nextIndex();
    }
    return -1;
}
  • 清除元素
public void clear() {
    removeRange(0, size());
}

protected void removeRange(int fromIndex, int toIndex) {
    ListIterator<E> it = listIterator(fromIndex);
    for (int i=0, n=toIndex-fromIndex; i<n; i++) {
        it.next();
        it.remove();
    }
}
  • Iterator 和 ListIterator的内部实现
    实现了AbstractCollection中抽象的iterator()方法,但是仍没有实现size()方法,因此其子类(非抽象子类)必须实现get()和size()两个方法;
    需要说明一下AbstractList中实现了两种迭代器:实现逻辑在Itr()和ListItr()中。
public Iterator<E> iterator() {
    return new Itr();
}

public ListIterator<E> listIterator() {
    return listIterator(0);
}

public ListIterator<E> listIterator(final int index) {
    rangeCheckForAdd(index);

    return new ListItr(index);
}
………… 
modCount

表示此列表已被数据结构中修改的次数。
modCount变量是fast-fail机制的一个重要变量,对元素有操作的做法都应该对这个变量进行变更,以维持fast-fail机制;

小结:

AbstractList从整体架构上完成了大部分底层方法的实现(查询方式、迭代器默认实现),但增删改的方法都没有具体的实现,内部的数据结构也没有实现;

为什么不一次性全部方法实现呢?

我认为在于数据结构的实现有多种形式(数组、链表等)每一种数据结构要求的数据操作都有不同,因此AbstractList从结构设计上仍处于一个中间阶段,还未到提供可直接使用对象的阶段。
至此,大家应该能明白AbstractList为何是抽象的?为何许多方法都没有完全实现,但是却内部实现了迭代的方式,也提供了基础的查找方法了吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值