笔记内容来自《数据结构与算法分析 Java语言描述》第三版


JavaSE|Java Collections API

  • Collection 接口
  • Iterator 接口
  • List 接口


在类库中,Java 语言包括一些普通的数据结构的实现。这一部分叫做 Collections API。Collections API 位于 java.util 包中。

Collection 接口

集合的概念在 Collection 接口中得到抽象,它存储一组类型相同的对象。

Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。

  • 一些 collection 允许有重复的元素,而另一些则不允许。
  • 一些 collection 是有序的,而另一些则是无序的。

JDK 不提供此接口的任何直接实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

public interface Collection<E> extends Iterable<E> { 
		int size();
		boolean isEmpty();
		void clear();
		boolean contains(E x);
		boolean add(E x);
		boolean remove(E x);
		Iterator<E> iterator();
}

Collection 接口扩展了 Iterable 接口。实现 Iterable 接口的类可以使用增强 for 循环。

Iterator 接口

实现 Iterable 接口的集合必须重写 iterator() 方法,该方法返回一个 Iterator 类型的对象。Iterator 是在 java.util 包中定义的接口。

public interface Iterator<E> {
		boolean hasNext();
		E next();
		void remove();
}

Iterator 是对 collection 进行迭代的迭代器。Collection 的子类通过 iterator 方法均可创建并返回给用户一个实现了 Iterator 接口的对象,该 对象内部存储 “当前位置” 的概念。

每次对 next() 的调用都给出集合的下一项。第一次调用 next() 给出第一项,以此类推。

增强 for 底层是通过 Iterator 对象实现的

for (Integer i : list) {
 	System.out.println(i);
}

以上代码反编译后得到以下代码:

Integer i;
for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
	 i = (Integer)iterator.next(); 
}

remove() 方法可以删除由 next() 最新返回的项。在使用迭代器时不应该混用被迭代集合的 remove() 、add() 等会引起被迭代集合结构发生变化的操作方法,否则迭代器不再合法,会抛出ConcurrentModificationException异常。

如下代码,会抛出ConcurrentModificationException异常。

for (Student stu : students) { 
 	if (stu.getId() == 2) 
 		students.remove(stu); 
}

Iterator是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException异常。

所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性

Iterator<Student> stuIter = students.iterator(); 
while (stuIter.hasNext()) { 
	Student student = stuIter.next(); 
 	if (student.getId() == 2) 
		 stuIter.remove();
}

List 接口

List 接口继承了 Collection 接口,包含 Collection 接口的所有方法,外加一些其他方法。观察 List 接口发现,用户可以通过使用get() 和 set() 方法访问或改变指定位置 idx 上的项。

  • 索引0位于表的前端;
  • 索引 size()-1 代表表中最后一项;
  • 索引 size() 表示要新添加的项可以被放置的位置。
public interface List<E> extends Collection<E> {
		E get(int idx);
		E set(int idex, E newVal);
		void add(int idx, E x);
		void remove(int idx);
		
		ListIterator<E> listIterator(int pos);
}