Java集合框架深度学习:从Iterable到ArrayList的完整继承体系

从源码上看ArrayList的继承关系如下图所示:

Iterable接口

Iterable接口是集合框架的顶层接口,表明"可迭代"/"可遍历查询"的能力。

Iterable有一个iterator方法,需要实现类重写该方法。

java 复制代码
Iterator<T> iterator(); // 返回一个迭代器对象,迭代器对象可对Iterable对象进行迭代遍历

Iterable有两个默认方法(已实现的方法):

java 复制代码
	//对 Iterable 的每个元素执行给定操作,直到处理完所有元素或操作引发异常
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
    
    //创建一个 Spliterator 用于遍历和分区此 Iterable 描述的元素
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }

Collection集合接口(以及它的所有子接口如 List, Set)继承Iterable接口,因此所有的集合对象都可以用迭代器,可以使用forEach方法来遍历元素执行函数。

java 复制代码
public class Demo8 {
    public static void main(String[] args) {
        // 创建一个Collection接口对象(Collection接口继承Iterable接口)
        Collection<String> list = new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

        // 创建一个迭代器对象
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }

        // 用forEach方法遍历集合
        list.forEach(s -> System.out.println(s));
    }
}

一般来说,我们不需要自定义实现Iterable接口的类,因为Java内置的集合框架已经够用了。但是如果你想让一个自定义的类实现增强for循环遍历,或者能够迭代遍历,就必须实现Iterable 接口。

Collection接口

Collection是集合类的根接口之一,Collection接口继承Iterable接口。

Collection的常用方法有:

  1. 基本操作方法
java 复制代码
// 返回集合中元素的数量
int size();

// 判断集合是否为空
boolean isEmpty();

// 判断是否包含指定元素
boolean contains(Object o);

// 向集合中添加元素(可选操作)
boolean add(E e);

// 从集合中移除元素(可选操作)
boolean remove(Object o);
  1. 批量操作方法
java 复制代码
// 判断是否包含指定集合的所有元素
boolean containsAll(Collection<?> c);

// 添加指定集合的所有元素(可选操作)
boolean addAll(Collection<? extends E> c);

// 移除与指定集合相同的所有元素(可选操作)
boolean removeAll(Collection<?> c);

// 仅保留与指定集合相同的元素(可选操作)
boolean retainAll(Collection<?> c);

// 清空集合(可选操作)
void clear();
  1. 数组转化方法
java 复制代码
// 返回包含所有元素的数组
Object[] toArray();

// 返回指定类型的数组
<T> T[] toArray(T[] a);
  1. Java 8+ 新增的默认方法
java 复制代码
// 返回顺序流
default Stream<E> stream()

// 返回并行流
default Stream<E> parallelStream()

// 根据条件删除元素
default boolean removeIf(Predicate<? super E> filter)
  1. 继承自Iterable的方法
java 复制代码
// 返回集合的迭代器
Iterator<E> iterator();

// 分割迭代器(用于并行处理)
default Spliterator<E> spliterator()

// 对 Iterable 的每个元素执行给定操作
void forEach(Consumer<? super T> action) 

注意:"可选操作"是指某些方法在某些具体实现类中可能不被支持,具体实现类可以在重写方法时抛出异常。

常用方法演示如下:

java 复制代码
public class Demo9 {
    public static void main(String[] args) {
        // 创建一个集合对象
        Collection<String> list = new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

        // 1. 基本操作方法
        // 返回集合中元素的数量
        System.out.println(list.size()); // 3
        // 判断集合是否为空
        System.out.println(list.isEmpty()); // false
        // 判断是否包含指定元素
        System.out.println(list.contains("hello")); // true
        // 向集合中添加元素(可选操作)
        list.add("python");
        System.out.println(list); // [hello, world, java, python]
        // 删除集合中的元素(可选操作)
        list.remove("java");
        System.out.println(list); // [hello, world, python]

        // 2. 批量操作方法
        // 判断是否包含指定集合的所有元素
        System.out.println(list.containsAll(list)); // true
        // 添加指定集合的所有元素(可选操作)
        Collection<String> list2 = new ArrayList<>();
        list2.add("this");
        list2.add("is");
        list2.add("a");
        list2.add("test");
        list.addAll(list2);
        System.out.println(list); // [hello, world, python, this, is, a, test]
        // 移除与指定集合相同的所有元素(可选操作)
        list.removeAll(list2);
        System.out.println(list); // [hello, world, python]
        // 仅保留与指定集合相同的元素(可选操作)
        list.addAll(list2);
        System.out.println(list); // [hello, world, python, this, is, a, test]
        list.retainAll(list2);
        System.out.println(list); // [this, is, a, test]
        // 清空集合(可选操作)
        list.clear();
        System.out.println(list); // []

        // 3. 数组转化方法
        Collection<String> list3 = new ArrayList<>();
        list3.add("ni");
        list3.add("hao");
        list3.add("ma");
        // 返回包含所有元素的数组
        Object[] arr = list3.toArray();
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
        // 返回指定类型的数组
        String[] arr2 = list3.toArray(new String[0]);
        for (int i = 0; i < arr2.length; i++) {
            System.out.println(arr2[i]);
        }
    }
}

AbstractCollection抽象类

AbstractCollection是一个实现Collection接口的抽象类,意味着它实现了一部分接口的方法,包括从Iterable间接继承的方法。

AbstractCollection实际上只有两个抽象方法没有实现,这两个方法都依赖具体实现类的数据结构。

java 复制代码
public abstract Iterator<E> iterator(); // 继承自Iterable
public abstract int size(); // 继承自Collection

AbstractCollection已经实现的方法,都是基于这两个抽象方法,以及从Collection接口直接继承和Iterable间接继承的默认实现方法来实现的。比如isEmpty()方法,是基于size() 方法实现:

java 复制代码
public boolean isEmpty() {
        return size() == 0;
    } // 基于size()方法实现

以下是一些已实现的方法:

  • isEmpty() - 基于 size() 实现
  • contains(Object o) - 基于迭代器遍历实现
  • toArray() - 基于迭代器和数组复制实现
  • toArray(T[] a) - 泛型版本,更复杂的数组处理
  • add(E e) - 默认抛出 UnsupportedOperationException
  • remove(Object o) - 基于迭代器遍历实现
  • containsAll(Collection< ?> c) - 基于 contains() 实现
  • addAll(Collection< ? extends E> c) - 基于迭代器和 add() 实现
  • removeAll(Collection< ?> c) - 基于迭代器和 contains() 实现
  • retainAll(Collection< ?> c) - 基于迭代器和 contains() 实现
  • clear() - 基于迭代器的 remove() 方法实现

为什么要专门编写一个AbstractCollection抽象类?这是因为这个抽象类,可以把框架的大部分方法实现,而到最后的具体实现类,只需要编写剩余很少的方法。也就是核心目的是减少重复代码,让具体集合类只关注核心数据结构。这种思路很适合一个接口具有多个实现类的场景。

List接口

List接口继承Collection接口,也就间接继承了Iterable接口,即继承了以上接口的所有方法。

List即"列表",可以理解是一类特殊的"集合",是一类有序、可被索引的集合。相比与Collection,List 对 equals() 和 hashCode() 有更严格的契约:

  1. 必须考虑元素的顺序
  2. 两个列表相等必须:大小相同 + 对应位置元素相等

List新增了一些方法,几乎都是跟索引有关,比如:

java 复制代码
E get(int index); //获取指定位置的元素
E set(int index, E element); // 替换指定位置的元素
void add(int index, E element); // 在指定位置插入元素
E remove(int index); // 移除指定位置的元素
int indexOf(Object o); // 返回元素第一次出现的索引
int lastIndexOf(Object o); // 返回元素最后一次出现的索引
boolean addAll(int index, Collection<? extends E> c); // 在指定位置插入集合中的所有元素
List<E> subList(int fromIndex, int toIndex); // 返回子列表视图

List接口,本身是继承了Iteratable接口的迭代Iterator相关方法。但List接口新定义了有关列表迭代器ListIterator相关方法:

java 复制代码
ListIterator<E> listIterator(); // 返回列表迭代器
ListIterator<E> listIterator(int index); // 从指定位置返回列表迭代器

ListIterator 比普通 Iterator 多了以下功能:

  1. 可以向前遍历(hasPrevious(), previous())
  2. 可以获取当前索引(nextIndex(), previousIndex())
  3. 可以在遍历时添加元素(add(E e))
  4. 可以在遍历时修改元素(set(E e))

另外,List接口也提供了一些默认实现的方法。

java 复制代码
// Java 8+ 引入的默认方法:
default void replaceAll(UnaryOperator<E> operator)  // 替换所有元素
default void sort(Comparator<? super E> c)          // 排序
default Spliterator<E> spliterator()               // 创建分割迭代器

// Java 9+ 引入的静态工厂方法:
static <E> List<E> of(E... elements)               // 创建不可修改列表
static <E> List<E> copyOf(Collection<E> coll)      // 创建副本

AbstractList抽象类

AbstractList是一个抽象类,它继承了AbstractCollection抽象类,又实现了List接口。因此,它继承了Iterable接口、Collection接口、List接口的所有方法,又继承了AbstractCollection的抽象和实现方法。

AbstractList和AbstractCollection作用相似,尽可能的实现List接口框架性的默认实现方法,仅保留少部分抽象方法,让子实现类去实现。

AbstractList 只要求子类必须实现两个核心方法:

java 复制代码
abstract E get(int index); 
abstract int size();

其他方法都是基于继承的默认方法,以及这两个核心方法的实现。

相关推荐
drebander2 小时前
Cursor IDE 中 Java 项目无法跳转到方法定义问题解决方案
java·ide·cursor
来不及辣哎呀2 小时前
学习Java第六十二天——Hot 100-09-438. 找到字符串中所有字母异位词
java·开发语言·学习
linsa_pursuer2 小时前
移动零算法
java·算法
lihao lihao2 小时前
模板进阶
java·数据结构·算法
鸿途优学-UU教育2 小时前
2025搜狐教育年度盛典|UU教育CEO彭普杰:成人学习不止于知识传递,科技赋能背后更需温度守护
科技·学习
山风wind2 小时前
Spring中责任链模式的工业级应用简单剖析
java·spring·责任链模式
冻伤小鱼干2 小时前
《自动驾驶与机器人中的slam技术:从理论到实践》笔记——ch7(4)
笔记·机器人·自动驾驶
后端小张2 小时前
【TextIn大模型加速器 + 火山引擎】TextIn大模型加速器与火山引擎协同构建智能文档处理新范式
人工智能·学习·数据挖掘·langchain·tensorflow·gpt-3·火山引擎
Element_南笙3 小时前
BUG:ModuleNotFoundError: No module named ‘milvus_lite‘
java·服务器·数据库