Collection接口_演练
参考:《java核心技术卷1》
引入
例.接口继承
假设有一个接口A
里面有一个方法A
:
package collection;
public interface InterfaceA {
void A();
}
另一个接口B
继承了接口A
并有一个方法B
:
package collection;
public interface InterfaceB extends InterfaceA {
void B();
}
问:现在有一个类C
实现了接口B
,那么类C
需要实现哪些方法?
package collection;
public class C implements InterfaceB {
// 类C不仅需要实现接口B中的方法B, 还需实现接口A中的方法A
public void A() {
}
public void B() {
}
public static void main(String[] args) {
C c = new C();
// 通过c可以调用哪些方法?
// 基于面向接口的思想 希望代码依赖于接口而不是实现 提高灵活性 也经常用接口变量来引用对象
// 由于 类C 既被强制实现了 interfaceB 的方法(不实现就报错,编译不通过)
// 也被强制实现了 interfaceA 的方法
// 即可用 interfaceB 的接口变量引用 类 C 对象
// 也可以用 interfaceA 的接口变量引用 类 C 对象
InterfaceB b = c;
InterfaceA a = c;
}
}
C实现B接口,不仅要实现B中的方法,还要实现(B的父接口)A中的方法。导致的结果是——在c上可以调用接口A和接口B中规定的所有方法。
集合框架中的接口
上述关系广泛存在于Java集合框架中。Java集合框架中的接口如图所示。
以ArrayList
和HashSet
为例子:
ArrayList
→ 实现了 → List
接口
List
接口 → 继承了 → Collection
接口
HashSet
→ 实现了 → Set
接口
Set
接口 → 继承了 → Collection
接口
虽然,ArrayList
和HashSet
感觉上差异很大,但是最终都实现了Collection
接口。(殊途同归!意味着它们都实现了Collection
接口中定义的抽象方法,可以说都具备Collection
的特性)
最后,Collection
接口 → 继承了 → Iterable
接口
Collection接口
简介
The root interface in the collection hierarchy. A collection represents a group of objects, known as its elements. Some collections allow duplicate elements and others do not. Some are ordered and others unordered.
集合层次结构中的根接口。一个collection
表示一组对象,称为它的元素。一些collection
允许重复元素,而另一些则不允许。有些是有序的,有些是无序的。
问:Set都是无序的吗?
基本方法
所有方法可参考官方文档:https://docs.oracle.com/javase/8/docs/api/
Collection
接口有两个最基本的方法:
boolean add(E e); // 确保此集合包含指定的元素
Iterator<E> iterator(); // 返回此集合中元素的迭代器
迭代器(★)
课本P254
凡是实现了Collection
接口的类,都有iterator
方法。(不管是直接实现、还是间接实现!)
iterator
方法用于返回一个实现了Iterator
接口的对象——该对象被称为迭代器。可以使用这个迭代器对象依次访问集合中的元素。
Iterator
接口包含4个方法(下面代码中对default
方法作了简化):
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove();
default void forEachRemaining(Consumer<? super E> action);
}
hasNext
方法是一种询问——(有没有)下一个元素?
next
方法——下一个元素!
通过反复调用next
方法,可以逐个访问集合中的每个元素。但是,如果到达了集合的末尾,next
方法将抛出一个NoSuchElementException
。因此,在调用next
之前需要调用hasNext
方法。如果迭代器对象还有更多可以访问的元素,这个方法就返回true
。如果想要查看集合中的所有元素,就请求一个迭代器,当hasNext
返回true
时就反复地调用next
方法。
例.迭代器
package collection;
import java.util.*;
public class IteratorTest {
public static void main(String[] args) {
List<String> list = new LinkedList<>();
list.add("123");
list.add("321");
list.add("1234");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println("访问list中的元素: " + element);
}
Set<String> set = new HashSet<>();
set.add("123");
set.add("321");
set.add("1234");
System.out.println("*****************************");
Iterator<String> iterator1 = set.iterator();
while (iterator1.hasNext()) {
String element = iterator1.next();
System.out.println("访问set中的元素: " + element);
}
}
}
上面代码中,list
和set
是如此的相似!都有add
和iterator
方法,这是因为它们都实现了collection
接口。
可以更加简洁地将这个循环写为for each
循环:
package collection;
import java.util.*;
public class IteratorTest {
public static void main(String[] args) {
List<String> list = new LinkedList<>();
list.add("123");
list.add("321");
list.add("1234");
for (String element : list) {
System.out.println("访问list中的元素: " + element);
}
Set<String> set = new HashSet<>();
set.add("123");
set.add("321");
set.add("1234");
System.out.println("*****************************");
for (String element : set) {
System.out.println("访问set中的元素: " + element);
}
}
}
编译器会把for each
循环转换为一个带迭代器的循环(可通过javap
验证)。
for each
循环实际上可以处理任何实现了Iterable
接口的对象。由于Collection
接口继承了Iterable
接口,因此实现Collection
接口就意味着必须同时实现Iterable
接口。
需注意的是!Iterable
接口并非Java集合框架专属,它可以用于任何需要提供迭代功能的类。
PS. for each
其实就是迭代器写法的简写形式,大部分场景下用for each
即可,小部分场景不得不用迭代器
其它方法
例.Collection通用方法
package collection;
import java.util.*;
public class IteratorTest {
public static void main(String[] args) {
List<String> list = new LinkedList<>();
// 1 add
list.add("123红红火火恍恍惚惚");
list.add("321");
list.add("1234");
// 5
list.remove("321");
for (String element : list) {
System.out.println("访问list中的元素: " + element);
}
Set<String> set = new HashSet<>();
// 2 addAll
set.addAll(list); // 将指定 collection 中的所有元素添加到此集合中
// 3
set.clear();
// 4 set.contains 如果此集合包含指定元素,则返回true
// 实际都学过,只是之前不知道是 在 collection 接口中规定的
System.out.println("*****************************");
for (String element : set) {
System.out.println("访问set中的元素: " + element);
}
set.addAll(list);
// 6
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
小结
凡实现了Collection
接口就可以调用Collection
中定义的方法,最常用的有add
、addAll
、clear
、contains
、iterator
、remove
Collection
接口继承了Iterable
接口,因此,实现了Collection
接口就一定可以用for each
循环访问元素。
for each
循环实际上是迭代器写法的一种简写形式
练习
练习1
本节最重要的是掌握迭代器的写法,以及Collection
中的常用方法。参考【例.Collection通用方法】熟悉写法。
练习2(★★★★★)
已知数组存放一批QQ号码,QQ号码最长为11位,最短为5位String[] strs = {"12345","67891","12347809933","98765432102","67891","12347809933"}
。 将该数组里面的所有qq号都存放在LinkedList
中,将list
中重复的元素删除,将list
中所有元素分别用迭代器
和增强for循环
打印出来。