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接口的基础实现,它实现了如下方法:

java 复制代码
public boolean addAll(Collection<? extends E> c)
public boolean contains(Object o)
public boolean containsAll(Collection<?> c)
public boolean isEmpty()
public boolean remove(Object o)
public boolean removeAll(Collection<?> c)
public boolean retainAll(Collection<?> c)
public void clear()
public Object[] toArray()
public <T> T[] toArray(T[] a)
public String toString()

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

java 复制代码
public boolean add(E e)
public abstract int size();
public abstract Iterator<E> iterator();

add方法的默认实现是:

java 复制代码
public boolean add(E e) {
       throw new UnsupportedOperationException();
}

代码抛出"操作不支持"异常,如果子类集合是不可被修改的,这个默认实现就可以了,否则,必须重写add方法。addAll方法的实现就是循环调用add方法。

size方法是抽象方法,子类必须重写。isEmpty方法就是检查size方法的返回值是否为0。toArray方法依赖size方法的返回值分配数组大小。

iterator方法也是抽象方法,它返回一个实现了迭代器接口的对象,子类必须重写。迭代器

定义了三个方法:

java 复制代码
boolean hasNext();
E next();
void remove();

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

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

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

java 复制代码
public class DynamicArray<E> {
       //...
       public E remove(int index) {
           E oldValue = get(index);
           int numMoved = size - index - 1;
           if(numMoved > 0)
               System.arraycopy(elementData, index + 1, elementData, index,
                       numMoved);
           elementData[--size] = null;
           return oldValue;
       }
       public void add(int index, E element) {
           ensureCapacity(size + 1);
           System.arraycopy(elementData, index, elementData, index + 1,
                            size - index);
           elementData[index] = element;
           size++;
       }
}

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

java 复制代码
public class DynamicArrayIterator<E>  implements Iterator<E>{
       DynamicArray<E> darr;
       int cursor;
       int lastRet = -1;
       public DynamicArrayIterator(DynamicArray<E> darr){
           this.darr = darr;
        }
    @Override
    public boolean hasNext() {
     return cursor != darr.size();
    }
    @Override
    public E next() {
        int i = cursor;
        if(i >= darr.size())
            throw new NoSuchElementException();
        cursor = i + 1;
    lastRet = i;
        return darr.get(i);
    }
    @Override
    public void remove() {
    if(lastRet < 0)
        throw new IllegalStateException();
    darr.remove(lastRet);
    cursor = lastRet;
    lastRet = -1;
}

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

java 复制代码
public class MyCollection<E> extends AbstractCollection<E> {
       DynamicArray<E> darr;
       public MyCollection(){
           darr = new DynamicArray<>();
       }
       public MyCollection(Collection<? extends E> c){
           this();
addAll(c); }
       @Override
       public Iterator<E> iterator() {
           return new DynamicArrayIterator<>(darr);
       }
       @Override
       public int size() {
           return darr.size();
       }
       @Override
       public boolean add(E e) {
           darr.add(e);
           return true;
       }
}
相关推荐
A__tao6 分钟前
JSON 转 Java 实体类工具(支持嵌套与注释解析)
java·python·json
zx2859634008 分钟前
Laravel6.x新特性全解析
java·后端·spring
极光代码工作室12 分钟前
基于SpringBoot的图书管理系统
java·springboot·web开发·后端开发
许彰午14 分钟前
# 从OOM到根治的完整过程——导出大数据的应急、根因分析与游标方案
java·大数据·数据库·系统架构
threelab23 分钟前
Three.js 咖啡杯烟雾效果 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能
上弦月-编程29 分钟前
C语言指针超详细教程——从入门到精通(面向初学者)
java·数据结构·算法
ANnianStriver31 分钟前
Java中的stream流的用法
java
1104.北光c°34 分钟前
【AI核心概念讲解】一口气搞懂 Agent:干翻传统后端!自主循环决策的秘密,ReAct 与 Plan-and-Execute 范式
java·人工智能·程序人生·ai·agent·react·智能体
初心未改HD36 分钟前
gRPC 与 Protobuf 实战指南
开发语言·golang
Jul1en_42 分钟前
Claude 迁移 Codex 工作流迁移与更新
java·服务器·前端·后端·ai编程