Java 集合 -- List

Java Collection 简介

Java标准库自带的java.util包提供了集合类:Collection,它是除Map外所有其他集合类的根接口。

Java的java.util包主要提供了以下三种类型的集合:

  • List:一种有序列表的集合,例如,按索引排列的Student的List;

  • Set:一种保证没有重复元素的集合,例如,所有无重复名称的Student的Set;

  • Map:一种通过键值(key-value)查找的映射表集合,例如,根据Student的name查找对应Student的Map。

Java Collection 接口的继承关系如下图:

Java集合的设计有几个特点:

  • 一是实现了接口和实现类相分离,例如,有序表的接口是List,具体的实现类有ArrayList,LinkedList等,

  • 二是支持泛型,我们可以限制在一个集合中只能放入同一种数据类型的元素,例如:

List<String> list = new ArrayList<>(); // 只能放入String类型

最后,Java访问集合总是通过统一的方式——迭代器(Iterator)来实现,它最明显的好处在于无需知道集合内部元素是按什么方式存储的。

部分遗留的集合类(不建议使用):

  • Hashtable:一种线程安全的Map实现;

  • Vector:一种线程安全的List实现;

  • Stack:基于Vector实现的LIFO的栈。

还有一小部分接口是遗留接口,也不应该继续使用

  • Enumeration:已被Iterator取代。

使用 List

在集合类中,List是最基础的一种集合:它是一种有序列表。List的索引和数组一样,从0开始。

List 的实现类 ArrayList

在实际应用中,需要增删元素的有序列表,我们使用最多的是ArrayList。实际上,ArrayList在内部使用了数组来存储所有元素。

ArrayList把添加和删除的操作封装起来,让我们操作List类似于操作数组,却不用关心内部元素如何移动。

List 的实现类 LinkedLsit

LinkedList通过“链表”也实现了List接口。在LinkedList中,它的内部每个元素都指向下一个元素.

比较一下ArrayList和LinkedList:

通常情况下,我们总是优先使用ArrayList。

List 的特点

List接口允许我们添加重复的元素,即List内部的元素可以重复:

public class ListMain {
    public static void main(String[] args){
        // 实例化一个 ArrayList 列表,命名为 list
        // 其中只能存放String 类型元素
        List<String> list = new ArrayList<>();
        list.add("apple"); // 使用 add()方法添加元素
        list.add("pear");
        list.add("apple");// 允许重复添加元素
        System.out.println(list.size()); // 使用size()方法获取列表长度
        System.out.println(list);
    }
}

List 允许添加 null

public class ListMain {
    public static void main(String[] args){
        // 实例化一个 ArrayList 列表,命名为 list
        // 其中只能存放String 类型元素
        List<String> list = new ArrayList<>();
        list.add("apple"); // 使用 add()方法添加元素
        list.add(null);
        list.add("apple");// 允许重复添加元素
        String second = list.get(1); // 获取列表元素,下标从0开始
        System.out.println(second);
        System.out.println(list);
    }
}

创建 List

除了使用ArrayList和LinkedList,我们还可以通过List接口提供的of()方法,根据给定元素快速创建List

List<Integer> list = List.of(1, 2, 5);

但是List.of()方法不接受null值,如果传入null,会抛出NullPointerException异常。

注意:只有JDK9及以上,才支持 of()方法快速创建List,JDK8不支持。

遍历 List

可以用for循环根据索引配合get()方法遍历:

public class ListMain {
    public static void main(String[] args){
        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("null");
        list.add("apple");
        for (int i=0; i<list.size(); i++){
            String s = list.get(i);
            System.out.println(s);
        }
    }
}

因为get(int)方法只有ArrayList的实现是高效的,换成LinkedList后,索引越大,访问速度越慢。

所以要始终坚持使用迭代器Iterator来访问List

Iterator本身也是一个对象,但它是由List的实例调用iterator()方法的时候创建的。

Iterator<String> it = list.iterator()

Iterator对象知道如何遍历一个List,并且不同的List类型,返回的Iterator对象实现也是不同的,但总是具有最高的访问效率。

Iterator对象有两个方法:

  • boolean hasNext()判断是否有下一个元素,

  • next()返回下一个元素。

因此,使用Iterator遍历List代码如下:

public class ListMain {
 public static void main(String[] args){
        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("null");
        list.add("apple");
        Iterator<String> iterator = list.iterator();
        for (;iterator.hasNext();){
            String s = iterator.next();
            System.out.println(s);
        }
    }
}

记住,通过Iterator遍历List永远是最高效的方式。

并且,由于Iterator遍历是如此常用,所以,Java的增强for循环本身就可以帮我们使用Iterator遍历。

把上面的代码再改写如下:

public class ListMain {
 public static void main(String[] args){
        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("null");
        list.add("apple");
        // Iterator<String> iterator = list.iterator();
        for (String s:list){ // 增强for循环
            // String s = iterator.next();
            System.out.println(s);
        }
    }
}

上述代码就是我们编写遍历List的常见代码。

实际上,只要实现了Iterable接口的集合类都可以直接用增强for循环来遍历.

Java编译器本身并不知道如何遍历集合对象,但它会自动把增强for循环变成Iterator的调用,原因就在于Iterable接口定义了一个Iterator iterator()方法,强迫集合类必须返回一个Iterator实例。

List 与 Array 的转换

array 表示数组。

把List变为Array有三种方法,

  • 第一种是调用toArray()方法直接返回一个Object[]数组

  • 第二种方式是给toArray(T[])传入一个类型相同的Array,List内部自动把元素复制到传入的Array中

  • 最后一种更简洁的写法是通过List接口定义的T[] toArray(IntFunction<T[]> generator)方法

每天学习一点点,每天进步一点点。

posted @ 2020-08-02 10:34  爱吃西瓜的番茄酱  阅读(308)  评论(0编辑  收藏  举报