• Java 抽象容器类源码剖析


    总体介绍

    抽象容器类接口和具体容器类的关系如图所示,顶层包括Collection、List、Set、Queue、Deque和Map6个抽象容器类。

    AbstractCollection:实现了Collection接口,被抽象类AbstractList、AbstractSet、AbstractQueue继承,ArrayDeque也继承自AbstractCollection。

    AbstractList:父类是AbstractCollection,实现了List接口,被ArrayList、Abstract-SequentialList继承。

    AbstractSequentialList:父类是AbstractList,被LinkedList继承。

    AbstractMap:实现了Map接口,被TreeMap、HashMap、EnumMap继承。

    AbstractSet:父类是AbstractCollection,实现了Set接口,被HashSet、 TreeSet和EnumSet继承。

    AbstractQueue:父类是AbstractCollection,实现了Queue接口,被PriorityQueue继承。

    本文分别介绍这些抽象类,包括它们提供的基础功能、如何实现、如何进行扩展等。

    以AbstractCollection为例

    AbstractCollection提供了Collection接口的基础实现,它实现了如下方法:

    1. public boolean addAll(Collection c)
    2. public boolean contains(Object o)
    3. public boolean containsAll(Collection c)
    4. public boolean isEmpty()
    5. public boolean remove(Object o)
    6. public boolean removeAll(Collection c)
    7. public boolean retainAll(Collection c)
    8. public void clear()
    9. public Object[] toArray()
    10. public T[] toArray(T[] a)
    11. public String toString()

    由于AbstractCollection不知道数据是怎么存储的,它依赖于如下更为基础的方法:

    1. public boolean add(E e)
    2. public abstract int size();
    3. public abstract Iterator iterator();

    add方法的默认实现是:

    1. public boolean add(E e) {
    2. throw new UnsupportedOperationException();
    3. }

    代码抛出“操作不支持”异常,如果子类集合是不可被修改的,这个默认实现就可以了,否则,必须重写add方法。addAll方法的实现就是循环调用add方法。
    size方法是抽象方法,子类必须重写。isEmpty方法就是检查size方法的返回值是否为0。toArray方法依赖size方法的返回值分配数组大小。
    iterator方法也是抽象方法,它返回一个实现了迭代器接口的对象,子类必须重写。迭代器
    定义了三个方法:

    1. boolean hasNext();
    2. E next();
    3. void remove();

    如果子类集合是不可被修改的,选代器不用实现remove方法,否则,三个方法都必须实现。

    除了接口中的方法,Collection接口文档建议,每个Collection接口的实现类都应该提供至少两个标准的构造方法,一个是默认构造方法,另一个接受一个Collection类型的参数。

    具体如何通过继承AbstractCollection来实现自定义容器呢?下面通过一个简单的例子来说明。我们使用自己实现的动态数组容器类DynamicArray来实现一个简单的Collection。

    1. public class DynamicArray {
    2. //...
    3. public E remove(int index) {
    4. E oldValue = get(index);
    5. int numMoved = size - index - 1;
    6. if(numMoved > 0)
    7. System.arraycopy(elementData, index + 1, elementData, index,
    8. numMoved);
    9. elementData[--size] = null;
    10. return oldValue;
    11. }
    12. public void add(int index, E element) {
    13. ensureCapacity(size + 1);
    14. System.arraycopy(elementData, index, elementData, index + 1,
    15. size - index);
    16. elementData[index] = element;
    17. size++;
    18. }
    19. }

    基于DynamicArray,再实现一个简单的迭代器类DynamicArrayIterator

    1. public class DynamicArrayIterator implements Iterator{
    2. DynamicArray darr;
    3. int cursor;
    4. int lastRet = -1;
    5. public DynamicArrayIterator(DynamicArray darr){
    6. this.darr = darr;
    7. }
    8. @Override
    9. public boolean hasNext() {
    10. return cursor != darr.size();
    11. }
    12. @Override
    13. public E next() {
    14. int i = cursor;
    15. if(i >= darr.size())
    16. throw new NoSuchElementException();
    17. cursor = i + 1;
    18. lastRet = i;
    19. return darr.get(i);
    20. }
    21. @Override
    22. public void remove() {
    23. if(lastRet < 0)
    24. throw new IllegalStateException();
    25. darr.remove(lastRet);
    26. cursor = lastRet;
    27. lastRet = -1;
    28. }

    基于DynamicArray和DynamicArrayIterator,通过继承AbstractCollection,我们来实现一个简单的容器类MyCollection。MyCollection提供了两个构造方法,并重写了size、add和iterator方法,这些方法内部使用了DynamicArray和DynamicArrayIterator。

    1. public class MyCollection extends AbstractCollection {
    2. DynamicArray darr;
    3. public MyCollection(){
    4. darr = new DynamicArray<>();
    5. }
    6. public MyCollection(Collection c){
    7. this();
    8. addAll(c); }
    9. @Override
    10. public Iterator iterator() {
    11. return new DynamicArrayIterator<>(darr);
    12. }
    13. @Override
    14. public int size() {
    15. return darr.size();
    16. }
    17. @Override
    18. public boolean add(E e) {
    19. darr.add(e);
    20. return true;
    21. }
    22. }

  • 相关阅读:
    Java 效率工具, 大幅度提高开发效率
    【Bluetooth|蓝牙开发】一、开篇词 | 打造全网最详细的Bluetooth开发教程
    JAVA 单例模式
    百余门店闭门谢客,韩妆如何败给了国潮?
    JavaWeb篇_03——Tomcat下载与安装,目录结构与介绍以及Tomcat启动与关闭
    Mybatis-Plus最新教程
    Git纯操作版 项目添加和提交、SSH keys添加、远程仓库控制、冲突解决、IDEA连接使用
    代码随想录算法训练营第六十二天 | 84.柱状图中最大的矩形
    Google Earth Engine(GEE)——用reducers来获取某一个区域得响应值并转化为列
    12 带音视频、多媒体、2D3D显示加速的嵌入式类芯片介绍
  • 原文地址:https://blog.csdn.net/cangshanjiang/article/details/136114662