![](https://img.haomeiwen.com/i11423226/5db0641142981b96.png)
可以看到Collection是最核心的接口,下面依次是AbstractCollection,AbstractList和AbstractSet,以及我们常用的ArrayList、LinkedList等等。
虽然看起来继承关系非常繁重和复杂,但是优点也很明显,学会Java的集合框架的人再去用C++的STL框架一定会觉得怎么这么难用啊,这也是Java的魅力所在了,各种官方框架设计合理,使用方便,多态性强。
拿一段百度上找来的话:
- 编码更轻松:Java 集合框架为我们提供了方便使用的数据结构和算法,让我们不用从头造轮子,直接操心上层业务就好了。
- 代码质量更上一层楼:Java 集合框架经过几次升级迭代,数据结构和算法的性能已经优化地很棒了。由于是针对接口编程,不同实现类可以轻易互相替换。这么优雅的设计,省下你自己磨练多少工夫,恩?!
- 减少学习新 API 的成本:过去每个集合 API 下还有子 API 来对 API 进行操作,你得学好几层才能知道怎么使用,而且还容易出错。现在好了!有了标准的 Java 集合框架,每个 API 都继承自己顶层 API,只负责具体实现,一口气学 5 个集合,不费劲!
*照猫画虎也容易多了:由于顶层接口已经把基础方法都定义好了,你只要实现接口,把具体实现方法填好,再也不用操心架构设计。
那么,首先我们就进入Collecion接口吧
Collection,也就是集合,不过和数学中的集合不太一样,根据官方文档,这里的集合既可以有重复元素,也可以没有重复元素,既可以有序,也可以无序,是用来实现多态的一个接口,具体包括我们常用的List和Set。
作为根接口,它定义了子类需要实现的19个方法:
![](https://img.haomeiwen.com/i11423226/2ac30e066d0efae3.png)
有对集合的基础操作:
- int size() 获取集合大小
- boolean isEmpty() 集合是否为空
- boolean contains(Object) 集合是否包含某个元素
- boolean add(E) 将元素加入集合,成功则返回true
- boolean remove(E) 将指定元素移除集合,成功则返回true
- Iterator iterator() 获取迭代器
还有一些批量操作:
-
boolean containsAll(Collection<?>)
如果此集合包含指定集合中所有元素则返回true -
boolean addAll(Collection<?>)
将指定集合中所有元素加入此集合,如果集合改变了则返回true -
boolean removeAll(Collection<?>)
删除所有指定集合中有的元素,如果集合改变了则返回true -
boolean retainAll(Collection<?>)
保留所有指定集合中有的元素,换句话说就是如果某个元素不在指定集合中,就删除它,也是集合改变就返回true -
clear() 清空整个集合
以及对数组操作的方法:
- Object[] toArray()
返回一个包含集合中所有元素的数组 - <T> T[] toArray(T[] a)
返回一个包含集合中所有元素的数组,运行时根据集合元素的类型指定数组的类型
遍历 Collection 的几种方式:
for-each语法
Collection<Person> persons = new ArrayList<Person>();
for (Person person : persons) {
System.out.println(person.name);
}
使用 Iterator 迭代器
Collection<Person> persons = new ArrayList<Person>();
Iterator iterator = persons.iterator();
while (iterator.hasNext) {
System.out.println(iterator.next);
}
使用 aggregate operations 聚合操作
Collection<Person> persons = new ArrayList<Person>();
persons
.stream()
.forEach(new Consumer<Person>() {
@Override
public void accept(Person person) {
System.out.println(person.name);
}
});
这里就要说一下第三种方法了,是Java 8推出的一种新型的、用来串行/并行处理集合的 API ,这种 API 用起来非常简洁高效,可读性也很不错,具体使用说明详见我写的这篇文章)
AbstractCollection
根据官方文档的解释,AbstractCollection提供给开发者一个Collection接口的基本实现,以减轻程序员的工作。
如果要实现一个不可修改其中元素的集合,那么只需要继承它然后重写size
和iterator
方法即可。
如果要实现可以修改元素的集合,那么还需要实现add
方法,对应的iterator
也要实现它的remove
方法。
也就是说,这个类就是把除了size
和iterator
方法以外的其他方法都给你实现了。
这里绝大多数方法都是用迭代器实现的,这里就抽几个有意思的方法来看一看。
public Object[] toArray() {
// Estimate size of array; be prepared to see more or fewer elements
Object[] r = new Object[size()];
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) // fewer elements than expected
return Arrays.copyOf(r, i);
r[i] = it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
这个函数就是将集合里的元素转换成数组,很简单的一个东西,不过这里考虑了很多特殊情况。例如如果 size
返回的个数比iterator
返回的元素多或者少的情况也考虑了(虽然我不知道为什么会有这种情况发生)
当iterator
里的元素个数比size
小的话很简单,重新赋值一个小的数组就好了。
而iterator
里的元素个数比size
大的话,这里调用了一个叫finishToArray
的方法:
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) {
int newCap = cap + (cap >> 1) + 1;
// overflow-conscious code
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next();
}
// trim if overallocated
return (i == r.length) ? r : Arrays.copyOf(r, i);
}
里面的newCap
就是新数组的容量,先是和数组的长度一致,若不够的话,再扩容原来尺寸的一半再加一,这和ArrayList
的扩容很相似,同样的,对数组分配过多也有处理。
网友评论