- 在集合类中,
List
是最基础的一种集合:它是一种有序列表。List
的行为和数组几乎完全相同,在添加和删除元素的时候,会非常不方便。因此,在实际应用中,需要增删元素的有序列表,我们使用最多的是ArrayList
。实际上,ArrayList
在内部使用了数组来存储所有元素。 ArrayList
把添加和删除的操作封装起来,让我们操作List
类似于操作数组,却不用关心内部元素如何移动。- 我们考察
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()
实现
List
接口并非只能通过数组(即ArrayList
的实现方式)来实现,另一种LinkedList
通过“链表”也实现了List接口。在LinkedList
中,它的内部每个元素都指向下一个元素:我们来比较一下
ArrayList
和LinkedList
: | | ArrayList | LinkedList | | :—- | :—- | :—- | | 获取指定元素 | 速度很快 | 需要从头开始查找元素 | | 添加元素到末尾 | 速度很快 | 速度很快 | | 在指定位置添加/删除 | 需要移动元素 | 不需要移动元素 | | 内存占用 | 少 | 较大 |
通常情况下,我们总是优先使用ArrayList
。
- List的特点
- 允许添加重复的元素
- 允许添加null
public class ListTest {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("apple");//size=1
list.add("pear"); //size=2
list.add("apple"); //size=3
list.add(null); //size=4
System.out.println(list.size());
System.out.println(list);
}
}
- 创建LIst的方法
- 使用
ArrayList
和LinkedList
- 通过
List
接口提供的of()
方法(JDK9新特性)List<Integer> list = List.of(1, 2, 5);
//但是List.of()方法不接受null值,如果传入null,会抛出NullPointerException异常。
- 遍历List的方法
for循环+索引
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");//size=1
list.add("pear"); //size=2
list.add("banana"); //size=3
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
}
}
但这种方式并不推荐,一是代码复杂,二是因为
get(int)
方法只有ArrayList
的实现是高效的,换成LinkedList
后,索引越大,访问速度越慢。使用迭代器
Iterator
来访问List
Iterator对象有两个方法:boolean hasNext()判断是否有下一个元素,E next()返回下一个元素。
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");//size=1
list.add("pear"); //size=2
list.add("banana"); //size=3
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
System.out.println(s);
}
}
}
由于Iterator
遍历是如此常用,所以,Java的for each
循环本身就可以帮我们使用Iterator
遍历。
for (String s : list) {
System.out.println(s);
}
List和Array的转换
List—>Array
调用
toArray()
方法直接返回一个Object[]
数组,这种方法会丢失类型信息,所以实际应用很少。Object[] array=list.toArray();
for (Object s:array){
System.out.println(s);
}
ii. 给
toArray(T[])
传入一个类型相同的Array
,List
内部自动把元素复制到传入的Array
中。public class Main {
public static void main(String[] args) {
List<Integer> list = List.of(12, 34, 56);
Integer[] array = list.toArray(new Integer[3]);
for (Integer n : array) {
System.out.println(n);
}
}
}
注意:如果传入的数组不够大,那么
List
内部会创建一个新的刚好够大的数组,填充后返回;如果传入的数组比List
元素还要多,那么填充完元素后,剩下的数组元素一律填充null
。
b. Array—>List通过
List.of(T...)
方法(JDK9)- 对于JDK 11之前的版本,可以使用
Arrays.asList(T...)
方法把数组转换成List
注意,如果我们调用Integer[] array1 = { 1, 2, 3 };
List<Integer> list2 = Arrays.asList(array);
System.out.println(list2);
List.of()
,它返回的是一个只读List,对只读List
调用add()
、remove()
方法会抛出UnsupportedOperationException
。