【Java语法栏——Java集合二】List接口

5 篇文章 0 订阅

一 List集合概念

1 List集合概念

在 Java 中,List 是一种常用的集合接口,它继承自 Collection 接口,表示一组有序的元素序列。List 接口允许按照插入顺序存储元素,并且允许通过索引(位置)来访问和修改元素。与集合不同,List 中的元素是可以重复的。


2 List 集合特点
  • 有序:存和取的元素顺序一致
  • 有索引:可以通过索引操作元素
  • 可重复:存储的元素可以重复

3 List实现类
  • ArrayList:底层是数组,线程不安全的,有序,可重复,有索引(使用场景:想要集合中的元素可以重复)
  • LinkedList:底层是双向链表,线程不安全的,有序,可重复,有索引(使用场景:想要集合中的元素可以重复,而且当前的增删操作明显多于查询的)
  • Vector:底层是数组,线程不安全的,有序,可重复,有索引


二 实现方式

采用多态的形式

List<Integer> integers=new ArrayList<>();
List<String> strings=new LinkedList<>();
List<Long> longs=new Vector<>();

三 常用方法

1 接口底层代码

首先我们先大概看一遍底层所写的方法,Java8(按顺序)。

import java.util.function.UnaryOperator;


public interface List<E> extends Collection<E> {
    // 集合操作

    //返回集合中元素的个数
    int size();

    //判断集合是否为空
    boolean isEmpty();

    //判断集合是否包含指定元素
    boolean contains(Object o);

    //内置迭代器
    Iterator<E> iterator();

    //将集合中的元素转换为一个数组
    Object[] toArray();

    //将集合中的元素转换为指定类型的数组。
    <T> T[] toArray(T[] a);


    // 修改操作
    //在集合中添加指定的元素
    boolean add(E e);

    //在集合中移除指定的元素
    boolean remove(Object o);


    // 批量修改

    //判断集合里面是否包含指定集合
    boolean containsAll(Collection<?> c);

    //将指定集合中的所有元素添加到调用该方法的集合中
    boolean addAll(Collection<? extends E> c);

    //将指定集合中的所有元素插入到调用该方法的列表中的指定位置
    boolean addAll(int index, Collection<? extends E> c);

    //从该集合中移除指定集合中的元素(重复元素也会被全部移除)
    boolean removeAll(Collection<?> c);

    //保留当前集合中与指定集合相交的元素
    boolean retainAll(Collection<?> c);

    //使用提供的 UnaryOperator(内含替换规则) 对列表中的每个元素进行替换操作
    default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }

    //排序
    @SuppressWarnings({"unchecked", "rawtypes"})
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

    
    //清除该集合中的所有元素
    void clear();


    // 比较与哈希

    //与指定对象作比较
    boolean equals(Object o);

    //返回一个哈希值
    int hashCode();


    // 位置访问操作

    //获取指定索引中的元素
    E get(int index);

    //设置指定位置上的值
    E set(int index, E element);

    //在指定位置上添加指定元素
    void add(int index, E element);

    //移除指定位置上的元素
    E remove(int index);


    // 查询操作

    //用于返回指定元素在列表中第一次出现的索引
    int indexOf(Object o);

    //用于返回指定元素在列表中最后一次出现的索引
    int lastIndexOf(Object o);


    // 列表迭代器

    //定义一个列表迭代器
    ListIterator<E> listIterator();

    //用于返回一个列表迭代器,该迭代器从列表中的指定位置开始遍历
    ListIterator<E> listIterator(int index);

    // 视图

    //返回一个新的列表,该列表包含了从 fromIndex(包括)到 toIndex(不包括)的元素
    List<E> subList(int fromIndex, int toIndex);

    //用于返回一个 Spliterator 对象,支持并行迭代操作
    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, Spliterator.ORDERED);
    }
}
int size();返回集合中元素的个数
boolean isEmpty();判断集合是否为空

boolean contains(Object o);

判断集合中是否包含指定元素

Iterator<E> iterator();

内置迭代器

Object[] toArray();

将集合中的所有元素转换为一个数组

<T> T[] toArray(T[] a);

将集合中的所有元素转换为一个指定类型的数组

boolean add(E e);

在集合中添加指定元素

boolean remove(Object o);

在集合中移除指定元素

boolean containsAll(Collection<?> c);

判断集合中是否包含指定集合

boolean addAll(Collection<? extends E> c);

将指定集合中的所有元素添加到集合中

boolean addAll(int index, Collection<? extends E> c);

将指定集合中的所有元素添加到集合中的指定位置

boolean removeAll(Collection<?> c);

从集合中移除指定集合中的所有元素

boolean retainAll(Collection<?> c);

保留当前集合中与传入集合相交的元素

default void replaceAll(UnaryOperator<E> operator)

使用提供的UnaryOperator(内含替换规则)对列表中的每个元素进行替换操作

default void sort(Comparator<? super E> c)

根据指定的比较器对列表进行排序

void clear();

清除该集合中的所有元素

boolean equals(Object o);

与指定对象作比较

int hashCode();

返回一个哈希值

E get(int index);

获取指定索引中的元素

E set(int index, E element);

设置指定索引中的元素

void add(int index, E element);

在指定位置上添加指定元素

E remove(int index);

移除指定位置上的元素

int indexOf(Object o);

返回指定元素在列表中第一次出现的索引

int lastIndexOf(Object o);

返回指定元素在列表中最后一次出现的索引

ListIterator<E> listIterator();

内置列表迭代器

ListIterator<E> listIterator(int index);

内置列表迭代器,从列表的指定位置开始遍历

List<E> subList(int fromIndex, int toIndex);

返回一个新的列表,包含了列表中[fromIndex,oIndex)的元素

default Spliterator<E> spliterator()

返回一个 Spliterator 对象,支持并行迭代操作

有一些是父接口都有的方法,前面也有讲到过,这里不再过多的赘述。


2 方法的实现

a.boolean add(E e);——添加指定元素

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]
    }
}

b.void add(int index, E element);——在指定位置上添加元素

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]
        strings.add(4,"!");
        System.out.println(strings);    //[hello, welcome, to, java, !]
    }
}

c.boolean remove(Object o);——移除指定元素

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]
        strings.remove("welcome");    //true
        strings.remove("!");    //false
        System.out.println(strings);    //[hello, to, java]
    }
}

d.E remove(int index);——移除指定位置上的元素

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]
        strings.remove(0);    //true
        strings.remove(2);    //true
        System.out.println(strings);    //[hello, to]
    }
}

e.E get(int index);——获取指定索引的元素

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]


        String s1 = strings.get(0);
        String s2 = strings.get(3);
        System.out.println(s1+","+s2);  //hello,java
    }
}

f.E set(int index, E element);——设置指定位置上的数值

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]


        strings.set(3,"Python");
        System.out.println(strings);  //[hello, welcome, to, Python]
    }
}

g.int size();——获取集合的个数

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]


        System.out.println(strings.size()); //4
    }
}

h.void clear();——清空集合中的元素

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]

        strings.clear();
        System.out.println(strings); //[]
    }
}

i.int indexOf(Object o);——获取指定元素第一次出现的位置

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]

        System.out.println(strings.indexOf("java")); //3
    }
}

j.int lastIndexOf(Object o);——获取指定元素最后一次出现的位置

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<String> strings=new ArrayList<>();
        strings.add("hello");    //true
        strings.add("welcome");    //true
        strings.add("to");    //true
        strings.add("java");    //true
        strings.add("java");    //true
        System.out.println(strings);    //[hello, welcome, to, java, java]

        System.out.println(strings.lastIndexOf("java")); //4
    }
}

3 总结
boolean add(E e);添加指定元素
void add(int index, E element);在指定位置上添加元素
boolean remove(Object o);移除指定元素
E remove(int index);移除指定位置上的元素
E get(int index);获取指定索引的元素
E set(int index, E element);设置指定位置上的数值
int size();获取集合的个数
void clear();清空集合中的元素
int indexOf(Object o);获取指定元素第一次出现的位置
int lastIndexOf(Object o);获取指定元素最后一次出现的位置

四 List集合的五种遍历方式

1 普通for循环
2 增强for循环
3 Lambda表达式
4 迭代器
5 列表迭代器
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class ListDemo {
    /**
     * 普通for循环
     * @param list
     */
    public void method1(List<String> list){
        for (int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }

    /**
     * 增强for循环
     * @param list
     */
    public void method2(List<String> list){
        for (String s:list){
            System.out.println(s);
        }
    }

    /**
     * Lambda表达式
     * @param list
     */
    public void method3(List<String> list){
        list.forEach(s-> System.out.println(s));
    }

    /**
     * 迭代器
     * @param list
     */
    public void method4(List<String> list){
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    public static void method5(List<String> list){
        ListIterator<String> stringListIterator = list.listIterator();
        // 与普通迭代器的区别:在遍历的过程中,可以在后面添加元素
        while (stringListIterator.hasNext()){
            String s=stringListIterator.next();
            if (s.equals("hello")){
                stringListIterator.add("java");
            }
        }
    }

    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("hello");
        list.add("!");
        method5(list);
        System.out.println(list);   //[hello, java, !]
    }
}

五 List集合的实现类ArrayList

1 概述
  • 是List集合的实现类,底层是数组结构实现,查询快,增删慢
  • 由于没有添加同步锁synchronized,所以是线程不安全的

2 方法的实现

由于是List集合的实现类,所以实现了List集合的所有方法


3 源码分析

扩容机制:

  1. 利用无参构造方法创建的集合,在底层创建一个默认长度为0的数组。
  2. 添加第一个元素时,底层会创建一个新的长度为10的数组。
  3. 存满时,会创建一个新的数组,为原来数组的1.5倍,将原来数组中的元素复制到新数组中。
  4. 如果一次添加多个元素,超过1.5倍的容量,则新创建数组的长度以实际为准。

关键要点:

  1. 数组名字elementData
  2. 数组长度size。这里size有两层含义:一是元素的个数;二是下一个元素的存入位置
  3. 添加元素,添加成功后,size++

底层代码:

//1 利用无参构造方法创建的集合,在底层创建一个默认长度为0的数组。

transient Object[] elementData;

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}




//2 添加第一个元素时,底层会创建一个新的长度为10的数组。
public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
}

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
}


//3 存满时,会创建一个新的数组,为原来数组的1.5倍,将原来数组中的元素复制到新数组中。
//4 如果一次添加多个元素,超过1.5倍的容量,则新创建数组的长度以实际为准。
private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
}

测试一下(注:下述示例中获取容量的方式使用了反射,这样的方式是为了演示,实际应用中请勿直接依赖于类的内部实现。)

import java.util.*;

public class ListDemo {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        // 默认初始容量是 0
        System.out.println("默认初始容量是:"+getCapacity(arrayList));
        System.out.println("Size: " + arrayList.size() + ", Capacity: " + getCapacity(arrayList));
        // 模拟一次存入一个数据
        for (int i = 0; i < 20; i++) {
            arrayList.add("Element " + i);
            System.out.println("Size: " + arrayList.size() + ", Capacity: " + getCapacity(arrayList));
        }
        // 模拟一次存入大量数据
        ArrayList<String> list=new ArrayList<>();
        for (int i=0;i<20;i++){
            list.add(String.valueOf(i));
        }
        arrayList.addAll(list);
        System.out.println("Size: " + arrayList.size() + ", Capacity: " + getCapacity(arrayList));
        System.out.println("存入大量数据时容量是:"+getCapacity(arrayList));
    }

    private static int getCapacity(ArrayList<?> arrayList) {
        // 通过反射获取 ArrayList 的容量
        try {
            java.lang.reflect.Field field = ArrayList.class.getDeclaredField("elementData");
            field.setAccessible(true);
            return ((Object[]) field.get(arrayList)).length;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return -1;
        }
    }
}


4 迭代器源码

这里主要列出关键的方法

ArrayList<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);

Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}

public Iterator<E> iterator() {
    return new Itr();
}

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    Itr() {}

    public boolean hasNext() {
        return cursor != size;
    }

    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
             throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
     }
}

图解:

结论:

在以后如何避免并发修改异常:在使用迭代器或者增强for循环对集合进行遍历操作的时候,不用使用集合的方法对集合进行增加和删除操作。


六 List集合的实现类LinkedList

1 概述
  • 是List集合的实现类,底层是双链表实现,查询慢,增删快
  • 由于没有添加同步锁synchronized,所以是线程不安全的

2 方法的实现

由于是List集合的实现类,所以实现了List集合的所有方法,并在其基础上新增了特有方法,下面列出几个较常用的方法(事实中也很少用到LinkedList的特有方法)

public void addFirst(E e)在该列表开头插入指定的元素
public void addLast(E e)将指定的元素追加到此列表的末尾
public E getFirst()返回此列表中的第一个元素
public   E getLast()返回此列表中的最后一个元素
ublic E removeFirst()从此列表中删除并返回第一个元素
public   E removeLast() 从此列表中删除并返回最后一个元素
import java.util.*;

public class ListDemo {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println(list);

        // public void addFirst(E e) | 在该列表开头插入指定的元素
        list.addFirst(0);
        System.out.println(list);   // [1, 2, 3]

        // public void addLast(E e)  | 将指定的元素追加到此列表的末尾
        list.addLast(4);    // [0, 1, 2, 3]

        // public E getFirst()       | 返回此列表中的第一个元素
        System.out.println(list.getFirst());    // 0

        // public   E getLast()      | 返回此列表中的最后一个元素
        System.out.println(list.getLast());     // 4

        // public E removeFirst()    | 从此列表中删除并返回第一个元素
        System.out.println(list.removeFirst());     // 0

        // public   E removeLast()   | 从此列表中删除并返回最后一个元素
        System.out.println(list.removeLast());      //4
    }
}

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值