1. 在集合类中,List是最基础的一种集合:它是一种有序列表。List的行为和数组几乎完全相同,在添加和删除元素的时候,会非常不方便。因此,在实际应用中,需要增删元素的有序列表,我们使用最多的是ArrayList。实际上,ArrayList在内部使用了数组来存储所有元素。
    2. ArrayList把添加和删除的操作封装起来,让我们操作List类似于操作数组,却不用关心内部元素如何移动。
    3. 我们考察List<E>接口,可以看到几个主要的接口方法:
    • 在末尾添加一个元素:boolean add(E e)
    • 在指定索引添加一个元素:boolean add(int index, E e)
    • 删除指定索引的元素:int remove(int index)
    • 删除某个元素:int remove(Object e)
    • 获取指定索引的元素:E get(int index)
    • 获取链表大小(包含元素的个数):int size()
    1. 实现List接口并非只能通过数组(即ArrayList的实现方式)来实现,另一种LinkedList通过“链表”也实现了List接口。在LinkedList中,它的内部每个元素都指向下一个元素:

      image.png

    2. 我们来比较一下ArrayListLinkedList: | | ArrayList | LinkedList | | :—- | :—- | :—- | | 获取指定元素 | 速度很快 | 需要从头开始查找元素 | | 添加元素到末尾 | 速度很快 | 速度很快 | | 在指定位置添加/删除 | 需要移动元素 | 不需要移动元素 | | 内存占用 | 少 | 较大 |

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

    1. List的特点
    • 允许添加重复的元素
    • 允许添加null
      1. public class ListTest {
      2. public static void main(String[] args) {
      3. List<String> list=new ArrayList<>();
      4. list.add("apple");//size=1
      5. list.add("pear"); //size=2
      6. list.add("apple"); //size=3
      7. list.add(null); //size=4
      8. System.out.println(list.size());
      9. System.out.println(list);
      10. }
      11. }
    1. 创建LIst的方法
    • 使用ArrayListLinkedList
    • 通过List接口提供的of()方法(JDK9新特性)
      1. List<Integer> list = List.of(1, 2, 5);
      2. //但是List.of()方法不接受null值,如果传入null,会抛出NullPointerException异常。
    1. 遍历List的方法
    • for循环+索引

      1. public class Main {
      2. public static void main(String[] args) {
      3. List<String> list = new ArrayList<>();
      4. list.add("apple");//size=1
      5. list.add("pear"); //size=2
      6. list.add("banana"); //size=3
      7. for (int i = 0; i < list.size(); i++) {
      8. String s = list.get(i);
      9. System.out.println(s);
      10. }
      11. }
      12. }

      但这种方式并不推荐,一是代码复杂,二是因为get(int)方法只有ArrayList的实现是高效的,换成LinkedList后,索引越大,访问速度越慢。

    • 使用迭代器Iterator来访问List

    Iterator对象有两个方法:boolean hasNext()判断是否有下一个元素,E next()返回下一个元素。

    1. public class Main {
    2. public static void main(String[] args) {
    3. List<String> list = new ArrayList<>();
    4. list.add("apple");//size=1
    5. list.add("pear"); //size=2
    6. list.add("banana"); //size=3
    7. for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
    8. String s = it.next();
    9. System.out.println(s);
    10. }
    11. }
    12. }

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

    1. for (String s : list) {
    2. System.out.println(s);
    3. }
    1. List和Array的转换

      1. List—>Array

        1. 调用toArray()方法直接返回一个Object[]数组,这种方法会丢失类型信息,所以实际应用很少。

          1. Object[] array=list.toArray();
          2. for (Object s:array){
          3. System.out.println(s);
          4. }

          ii. 给toArray(T[])传入一个类型相同的ArrayList内部自动把元素复制到传入的Array中。

          1. public class Main {
          2. public static void main(String[] args) {
          3. List<Integer> list = List.of(12, 34, 56);
          4. Integer[] array = list.toArray(new Integer[3]);
          5. for (Integer n : array) {
          6. System.out.println(n);
          7. }
          8. }
          9. }

          注意:如果传入的数组不够大,那么List内部会创建一个新的刚好够大的数组,填充后返回;如果传入的数组比List元素还要多,那么填充完元素后,剩下的数组元素一律填充null
          b. Array—>List

        2. 通过List.of(T...)方法(JDK9)

        3. 对于JDK 11之前的版本,可以使用Arrays.asList(T...)方法把数组转换成List
          1. Integer[] array1 = { 1, 2, 3 };
          2. List<Integer> list2 = Arrays.asList(array);
          3. System.out.println(list2);
          注意,如果我们调用List.of(),它返回的是一个只读List,对只读List调用add()remove()方法会抛出UnsupportedOperationException