List接口常用方法及其子类ArrayList, LinkedList, Vector的学习笔记

本文围绕Java的List接口展开,介绍了其主要实现类ArrayList、LinkedList和Vector的特点与使用场景。还阐述了List集合的四种遍历方式,以及两种删除集合元素的方法,并解释不能用某些方式删除的原因。此外,讲解了Java比较器(Comparator)的使用及示例代码。

List Interface

常用方法

返回值类型方法名方法描述
voidadd(int index, E element)在此集合中的指定位置插入指定元素。
booleanadd(E e)将指定的元素附加到此集合的末尾。
booleanaddAll(int index, Collection<? extends E> c)将指定集合中的所有元素插入此列表,从指定位置开始。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素追加到此列表的末尾,按照它们由指定集合的迭代器返回的顺序。
voidclear()从此集合中删除所有元素。
Objectclone()返回此实例的浅克隆副本。
booleancontains(Object o)返回此集合是否包含指定元素。
booleanequals(Object o)比较指定对象与此集合是否相等。
voidforEach(Consumer<? super E> action)对集合的每个元素执行给定的操作,直到处理完所有元素或操作引发异常。
Eget(int index)返回此集合中指定位置的元素。
intindexOf(Object o)返回此集合中指定元素第一次出现的索引,如果此集合不包含该元素返回 -1。
booleanisEmpty()如果此集合不包含任何元素返回true。
Iteratoriterator()获取此集合中元素的迭代器。
intlastIndexOf(Object o)返回此集合中指定元素最后一次出现的索引,如果此列表不包含该元素返回 -1。
Eremove(int index)移除此集合中指定位置的元素。
booleanremove(Object o)从此集合中移除第一次出现的指定元素(如果存在)。
booleanremoveAll(Collection<?> c)从此集合中移除指定集合中包含的所有元素。
booleanretainAll(Collection<?> c)仅保留此列表中包含在指定集合中的元素。
Eset(int index, E element)用指定元素替换此列表中指定位置的元素。
intsize()返回此集合中的元素数。
List<E>subList(int fromIndex, int toIndex)返回此集合中指定 fromIndex (可以取到)和 toIndex (取不到)之间的部分的集合。
Object[]toArray()返回一个数组,其中包含此集合中所有元素。
<T> T[]toArray(T[] a)以正确的顺序(从第一个元素到最后一个元素)返回一个包含此集合中所有元素的数组;返回数组类型是指定数组a的类型。
voidtrimToSize()将此集合的容量修剪为集合的当前大小

List 接口主要实现类:ArrayList

ArrayList经常被称为动态数组,但是又不同于数组。它是一个容器,用来存储数据。

  • ArrayList 是 List 接口的主要实现类
  • 本质上,ArrayList 是对象引用的一个”变长”数组

Arrays.asList(…) 方法返回的 List 集合,既不是 ArrayList 实例,也不是 Vector 实
例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合

![[Images/Pasted image 20230906193344.png]]

创建ArrayList对象的步骤如下:

  • 第⼀步:创建ArrayList容器对象。⼀般使⽤空参数构造⽅法,如下图所⽰:
  • 第⼆步:调⽤ArrayList类的常⽤⽅法对容器中的数据进⾏操作。常⽤⽅法如下:
构造方法描述
public ArrayList()创建一个空的集合对象。
public ArrayList(Collection<? extends E> c)创建一个包含指定集合所有元素的集合对象。
public ArrayList(int initialCapacity)创建一个初始容量为 initialCapacity 的集合对象。

List 的实现类之二:LinkedList

  • 对于频繁的插入或删除元素的操作,建议使用 LinkedList 类,效率较高。这是由底层采用链表(双向链表)结构存储数据决定的。

![[Images/Pasted image 20230906193517.png]]
特有方法:

  • void addFirst(Object obj): 在队列头部插入指定元素。
  • void addLast(Object obj): 在队列尾部插入指定元素。
  • Object getFirst(): 返回队列头部的元素。
  • Object getLast(): 返回队列尾部的元素。
  • Object removeFirst(): 移除并返回队列头部的元素。
  • Object removeLast(): 移除并返回队列尾部的元素。

List 的实现类之三:Vector

  • Vector 是一个古老的集合,JDK1.0 就有了。大多数操作与 ArrayList 相同,区别之处在于 Vector 是线程安全的。
  • 在各种 List 中,最好把 ArrayList 作为默认选择。当插入、删除频繁时,使用 LinkedList;Vector 总是比 ArrayList 慢,所以尽量避免使用。

特有方法:

  • void addElement(Object obj): 将指定的元素添加到Vector的末尾。
  • void insertElementAt(Object obj, int index): 在指定的索引位置插入指定的元素。
  • void setElementAt(Object obj, int index): 将指定索引位置的元素设置为指定的值。
  • void removeElement(Object obj): 移除Vector中指定的元素的第一个匹配项。
  • void removeAllElements(): 移除Vector中的所有元素。

List集合的遍历⽅式

List集合支持随机访问,所以有以下四种遍历方式

  • 普通for循环(有序,意味着有索引)
  • 迭代器
  • 增强for
  • Lambda表达式

以下是四种遍历集合的方法

PS:每种方法遍历后最好使用instanceof进行判断,然后输出

  1. 使用Iterator输出:
System.out.println("Iterator输出");  
Iterator ite = newVec.iterator();  
while (ite.hasNext()) {  
    System.out.println((String) ite.next());  
}

这种方法使用了Java的Iterator接口来遍历集合,通过iterator()方法获取一个迭代器,然后使用hasNext()next()方法逐个访问元素。

  1. 使用for循环:
System.out.println("for循环");  
for (int i = 0; i < newVec.toArray().length; i++) {  
    System.out.println(newVec.get(i));  
}

这种方法使用传统的for循环来遍历集合,通过索引来获取集合中的元素。需要使用toArray()方法将集合转换为数组。

  1. 使用for-each循环:
System.out.println("for-each循环");  
for (Object obj : newVec) {  
    System.out.println(obj);  
}

这种方法使用了Java的for-each循环,也称为增强型for循环。它会自动遍历集合中的所有元素,不需要索引。

  1. 使用for-each(Consumer)接口方法:
System.out.println("for each (Consumer)接口");  
newVec.forEach(new Consumer() {  
    @Override  
    public void accept(Object o) {  
        System.out.println(o);  
    }  
});

这种方法使用了Java 8引入的forEach方法,结合了Lambda表达式和Consumer接口,用于遍历并处理集合中的每个元素。

  1. 使用for-each Lambda表达式:
System.out.println("for-each Lambda表达式");  
newVec.forEach((o) -> System.out.println(o));

这种方法是上一个方法的Lambda表达式版本,更简洁。Lambda表达式允许您以更紧凑的方式定义操作,更容易阅读和编写。

Lambda表达式里不能给实例赋值,常量数组除外

这些方法中的每一种都可以用来遍历和打印集合中的元素,您可以根据具体的情况选择最适合您的方法。

以下是两种删除集合中元素的方法

步骤

  • 遍历集合
  • 判断字符串是否包含待删除元素
  • 如果包含就删除

先说结论,只有Iterator(remove()Method)和for i才能进行删除操作

方法一:

for (int i = 0; i < arrayList.size(); i++) {
    String str = (String) arrayList.get(i);
    if (str.contains("抱枕")) {
        arrayList.remove(str);
        i--;
    }
}

方法二:

Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
    String str = (String) iterator.next();
    System.out.println(str);
    if (str.contains("抱枕")) {
        iterator.remove();
    }
}

这两种方法都是用于从ArrayList中删除包含特定字符串的元素。方法一使用了传统的for循环,而方法二使用了迭代器(Iterator)来实现删除操作。方法二的好处是可以避免在迭代过程中修改集合造成的ConcurrentModificationException异常。

为什么不能获取Iterator.next()进行删除

Iterator的 next() 方法会进行检验,检验修改次数与期望的修改次数是否一样,只要有 remove 或者 add 操作,modCount 都会 修改,而 expectedModCount 创建对象的时候初始化好了,不会进行修改。

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

// 解决方法是使用迭代器的remove方法
public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet; // 让迭代器对象指向上一个
        lastRet = -1;
        expectedModCount = modCount; // 修改了expectedModCount
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

为什么不能使用foreach进行删除

forEach() ,如果在迭代过程中,存在 remove 或者 add 操作, modCount 都会 修改,而 expectedModCount 只是在第一次进入方法的时候赋值了

public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount; // 保存了进入到该方法之前集合修改次数
    final Object[] es = elementData;
    final int size = this.size;
    
    for (int i = 0; modCount == expectedModCount && i < size; i++) { // 判断集合的总修改次数和期望的修改次数是否一样
        action.accept(elementAt(es, i));
    }
    
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

比较器相关问题

当涉及到在Java中进行对象的比较时,通常需要使用比较器(Comparator)。比较器是一种实现了Comparator接口的类,它定义了一种比较两个对象的方法。下面是有关Java比较器的笔记和示例代码:

Java比较器(Comparator)

  1. Comparator接口:Java的Comparator接口是一个泛型接口,它定义了用于比较两个对象的方法。比较器允许我们根据自定义的比较规则来排序对象。

  2. 比较方法Comparator接口的主要方法是compare(T o1, T o2),其中o1o2是要比较的对象。该方法返回一个整数值,表示两个对象的比较结果:

    • 返回负数表示o1小于o2
    • 返回零表示o1等于o2
    • 返回正数表示o1大于o2

示例代码

下面是一些使用比较器的示例代码:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Vector;

class QQCY {
    private int age;

    public QQCY(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "QQCY{" +
                "age=" + age +
                '}';
    }
}

public class ComparatorExample {
    public static void main(String[] args) {
        Vector<QQCY> vector = new Vector<>();
        vector.add(new QQCY(25));
        vector.add(new QQCY(18));
        vector.add(new QQCY(30));

        // 方法一:创建实现了Comparator接口的实现类对象
        vector.sort(new QQCYComparator());

        // 匿名类
        vector.sort(new Comparator<QQCY>() {
            @Override
            public int compare(QQCY q1, QQCY q2) {
                return q1.getAge() - q2.getAge();
            }
        });

        // 匿名类转换成lambda表达式
        vector.sort((q1, q2) -> q1.getAge() - q2.getAge());

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

class QQCYComparator implements Comparator<QQCY> {
    @Override
    public int compare(QQCY q1, QQCY q2) {
        return q1.getAge() - q2.getAge();
    }
}

在上述示例中,我们创建了一个QQCY类,该类具有一个age字段用于比较。然后,我们演示了三种不同的方法来使用比较器来对Vector中的QQCY对象进行排序。这些方法包括创建一个实现了Comparator接口的实现类对象、使用匿名类以及使用Lambda表达式。

比较器允许我们根据不同的比较规则来排序对象,从而灵活地满足不同的需求。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值