通常,程序总是根据运行时才知道的某些条件去创建对象,在此之前,不会知道所需对象的数量,甚至不知道确切的类型。在 Java 中,通过容器来解决这个普遍的编程问题。
Collections 与 Collection
Collections
是一个实用类,Collection
是一个基本接口。
1 | public class Collections {} |
1 | public interface Collection<E> extends Iterable<E> {} |
Iterable 与 Iterator
Iterable
拥有产生 Iterator
的方法,但是并不拥有迭代状态,比如,当前元素。
Iterator
拥有迭代状态,主要体现在 hasNext()
,next
这些方法上。
1 | public interface Iterable<T> { |
1 | public interface Iterator<E> { |
添加一组元素
Arrays.asList()
方法接受一个数组或是一个用逗号分隔的元素列表,并将其转换为一个 List
对象。
Arrays.asList()
返回的 list
,底层是一个固定大小的数组,不能调整尺寸。试图使用 add()
或 delete()
方法在这种列表中添加或删除元素,就有可能会引发去改变数组尺寸的尝试,得到异常。
1 | List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); |
Collections.addAll()
方法接受一个 Collection
对象,以及一个数组或是一个用逗号分割的列表,将元素添加到 Collection
对象中。
1 | Integer[] integers = {6, 7}; |
容器的打印
1 | class F { |
subList()
subList()
方法允许你很容易地从较大的列表中创建出一个片断,但需要注意的是,subList()
所产生的列表的幕后就是初始列表,因此,对所返回的列表的修改都会反映到初始列表中。
1 | List<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5)); |
由于 subList()
所产生的列表拥有原始列表的引用,所以在这期间,原始列表所占用的空间并没有被垃圾回收器回收。当原始列表很大时,容易造成内存泄漏。
1 | List<List<Integer>> lists = new ArrayList<List<Integer>>(); |
迭代器
迭代器是一个对象,它的工作是遍历并选择序列中的对象。
arrayList.iterator().next()
实现:
1 | public E next() { |
arrayList.iterator().remove()
实现:
1 | public void remove() { |
ListIterator
是 Iterator
的子类型,支持双向移动,还可以替换访问过的最后一个元素。
arrayList.listIterator().previous()
实现:
1 | public E previous() { |
arrayList.listIterator().set()
实现:
1 | public void set(E e) { |
Collection 与 Iterator
1 | class K { |
forEach 与 迭代器
Collection
之所以能够使用 forEach
,是因为 Collection
继承了 Iterable
。
对于 forEach
,可以用于数组或其他任何实现了 Iterable
的类。
1 | class K { |
在 forEach
里面,如果想要拥有多种不同的遍历方法(例如从后向前,或者随机遍历),可以采用 适配器方法
。即,创建不同的方法,返回不同的 Iterable
对象。
1 | class K { |
Collections.shuffle()
1 | // 原数组顺序也会被打乱 |