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 接口

虽然,ArrayListHashSet感觉上差异很大,但是最终都实现了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);
        }
    }
}

上面代码中,listset是如此的相似!都有additerator方法,这是因为它们都实现了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中定义的方法,最常用的有addaddAllclearcontainsiteratorremove

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循环打印出来。

posted @ 2024-12-04 16:33  xkfx  阅读(69)  评论(0编辑  收藏  举报