前言
集合作为java中一个重要的组成部分,必须攻克!
什么是集合
在我看来,从本质上来说,集合首先是一个容器,里面可以存放数据,不管是基本类型还是其他类型的数据。从作用上来说,集合又提供了一些方法,能对存放在里面的数据进行操作,增删查等等。
什么是集合框架
在java 2 之前,已经有许多类来存储和操作数据对象,但是没有一个统一的标准,使得使用不同的集合类有很大的不同,而为了解决这个问题,建立了一个围绕一组标准接口的一整个集合框架。
集合框架是一个用来代表和操纵集合的统一架构。
所有的集合框架都包含如下内容:
接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
引用自菜鸟教程
集合框架整体架构
从图中可以看出,集合框架主要分为两部分,一部分为Collection,一部分为Map。
Collection及其实现类,都是存放的相同数据类型的数据。
Map及其实现类,是存储键值对类型的数据。
Collection
前面我们已经介绍过Iterator和ListIterator这两个接口了。今天开始分析Collection及其子类和实现类的源码。
方法
Collection作为一个根接口,为我们提供了以上这些方法。主要可以分成以下几类:
基础操作
int size();
boolean isEmpty();
boolean contains(Object o);
boolean add(E e);
boolean remove(Object o);
boolean equals(Object o);
int hashCode();
对整个集合的操作
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c)
对数组的操作
Object[] toArray();
<T> T[] toArray(T[] a);
jdk 8 新增的方法
default Spliterator<E> spliterator()
default Stream<E> stream()
default Stream<E> parallelStream()
注意
需要注意的是,虽然我们的图上,Collection类看上去是直接继承了Iterator类,但是实际上
public interface Collection<E> extends Iterable<E>
Collection接口是继承了Iterable这个接口。
Iterable接口
那么,这又是哪个接口呢,好像在图上没有显示嘛?
我们再来看Iterable接口的源码
/**
* 返回一个元素类型为T的迭代器
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
Iterator<T> iterator();
其实里面主要的就是这个方法,至于jdk 8 新增的两个方法暂时放在一边。
看源码里面不就是一个Iterator吗,那为什么Collection类包括它的子接口类List和Set都是继承Iterable而不是直接继承Iterator的呢?
通过度年,查到了相关解释
Iterator、Iterable接口的使用及详解
文中解释了为什么要继承Iterable,而不是直接继承Iterator
为什么一定要去实现Iterable这个接口呢? 为什么不直接实现Iterator接口呢?
看一下JDK中的集合类,比如List一族或者Set一族,
都是继承了Iterable接口,但并不直接继承Iterator接口。
仔细想一下这么做是有道理的。因为Iterator接口的核心方法next()或者hasNext()
是依赖于迭代器的当前迭代位置的。
如果Collection直接继承Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。
当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。
除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。
但即时这样,Collection也只能同时存在一个当前迭代位置。
而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。
多个迭代器是互不干扰的。