List Interface
常用方法
| 返回值类型 | 方法名 | 方法描述 |
|---|---|---|
void | add(int index, E element) | 在此集合中的指定位置插入指定元素。 |
boolean | add(E e) | 将指定的元素附加到此集合的末尾。 |
boolean | addAll(int index, Collection<? extends E> c) | 将指定集合中的所有元素插入此列表,从指定位置开始。 |
boolean | addAll(Collection<? extends E> c) | 将指定集合中的所有元素追加到此列表的末尾,按照它们由指定集合的迭代器返回的顺序。 |
void | clear() | 从此集合中删除所有元素。 |
Object | clone() | 返回此实例的浅克隆副本。 |
boolean | contains(Object o) | 返回此集合是否包含指定元素。 |
boolean | equals(Object o) | 比较指定对象与此集合是否相等。 |
void | forEach(Consumer<? super E> action) | 对集合的每个元素执行给定的操作,直到处理完所有元素或操作引发异常。 |
E | get(int index) | 返回此集合中指定位置的元素。 |
int | indexOf(Object o) | 返回此集合中指定元素第一次出现的索引,如果此集合不包含该元素返回 -1。 |
boolean | isEmpty() | 如果此集合不包含任何元素返回true。 |
Iterator | iterator() | 获取此集合中元素的迭代器。 |
int | lastIndexOf(Object o) | 返回此集合中指定元素最后一次出现的索引,如果此列表不包含该元素返回 -1。 |
E | remove(int index) | 移除此集合中指定位置的元素。 |
boolean | remove(Object o) | 从此集合中移除第一次出现的指定元素(如果存在)。 |
boolean | removeAll(Collection<?> c) | 从此集合中移除指定集合中包含的所有元素。 |
boolean | retainAll(Collection<?> c) | 仅保留此列表中包含在指定集合中的元素。 |
E | set(int index, E element) | 用指定元素替换此列表中指定位置的元素。 |
int | size() | 返回此集合中的元素数。 |
List<E> | subList(int fromIndex, int toIndex) | 返回此集合中指定 fromIndex (可以取到)和 toIndex (取不到)之间的部分的集合。 |
Object[] | toArray() | 返回一个数组,其中包含此集合中所有元素。 |
<T> T[] | toArray(T[] a) | 以正确的顺序(从第一个元素到最后一个元素)返回一个包含此集合中所有元素的数组;返回数组类型是指定数组a的类型。 |
void | trimToSize() | 将此集合的容量修剪为集合的当前大小 |
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进行判断,然后输出
- 使用Iterator输出:
System.out.println("Iterator输出");
Iterator ite = newVec.iterator();
while (ite.hasNext()) {
System.out.println((String) ite.next());
}
这种方法使用了Java的Iterator接口来遍历集合,通过iterator()方法获取一个迭代器,然后使用hasNext()和next()方法逐个访问元素。
- 使用for循环:
System.out.println("for循环");
for (int i = 0; i < newVec.toArray().length; i++) {
System.out.println(newVec.get(i));
}
这种方法使用传统的for循环来遍历集合,通过索引来获取集合中的元素。需要使用toArray()方法将集合转换为数组。
- 使用for-each循环:
System.out.println("for-each循环");
for (Object obj : newVec) {
System.out.println(obj);
}
这种方法使用了Java的for-each循环,也称为增强型for循环。它会自动遍历集合中的所有元素,不需要索引。
- 使用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接口,用于遍历并处理集合中的每个元素。
- 使用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)
-
Comparator接口:Java的
Comparator接口是一个泛型接口,它定义了用于比较两个对象的方法。比较器允许我们根据自定义的比较规则来排序对象。 -
比较方法:
Comparator接口的主要方法是compare(T o1, T o2),其中o1和o2是要比较的对象。该方法返回一个整数值,表示两个对象的比较结果:- 返回负数表示
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表达式。
比较器允许我们根据不同的比较规则来排序对象,从而灵活地满足不同的需求。
本文围绕Java的List接口展开,介绍了其主要实现类ArrayList、LinkedList和Vector的特点与使用场景。还阐述了List集合的四种遍历方式,以及两种删除集合元素的方法,并解释不能用某些方式删除的原因。此外,讲解了Java比较器(Comparator)的使用及示例代码。
847





