笔记内容来自《数据结构与算法分析 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);
}