一、概念
List接口是Collection接口的子接口,是一种有序、可重复的集合
二、常见方法
其他详细的部分可以查阅API
三、常用的实现类
1)ArrayList
List list1 = new ArrayList();
底层数据结构是数组,查询快,增删慢;线程不安全,效率高。
ArrayList和Vector中数组的初始化容量都是10。
如果要考虑多线程安全问题,建议使用Collections.synchronizedList()方法将ArrayList转成线程安全的集合,而不使用Vector集合。
注意,ArrayList中的元素:
1.允许为空
2.允许重复
3.有序
4.线程不安全
5.遍历时使用for循环速度高于foreach循环

1 public class ArrayListDemo { 2 public static void main(String[] args) { 3 List<Hero> heros = new ArrayList<>(); 4 //集合的添加 5 heros.add(new Hero("爆破")); 6 heros.add(new Hero("龙卷")); 7 heros.add(new Hero("银色獠牙")); 8 heros.add(new Hero("King")); 9 //集合的遍历:iterator方式 10 Iterator<Hero> it = heros.iterator(); 11 while(it.hasNext()) { 12 Hero hero = it.next(); 13 System.out.println(hero.name); 14 } 15 //修改,因为底层封装了一个数组,所以索引从0开始 16 heros.set(0, new Hero("秃头披风侠")); 17 //获取 18 System.out.println(heros.get(0).name); 19 //批量删除,单个删除用remove 20 heros.removeAll(heros); 21 System.out.println(heros.size()); 22 } 23 } 24 25 class Hero { 26 String name; 27 28 public Hero(String name) { 29 this.name = name; 30 } 31 }
有一点需要注意的是,在遍历List的过程中不可以使用remove的方式删除元素

1 public class ArrayListDemo { 2 public static void main(String[] args) { 3 List<Hero> heros = new ArrayList<>(); 4 //集合的添加 5 heros.add(new Hero("爆破")); 6 heros.add(new Hero("龙卷")); 7 heros.add(new Hero("银色獠牙")); 8 heros.add(new Hero("King")); 9 //在遍历的过程中使用remove删除 10 for (Hero hero : heros) { 11 if(hero.name.equals("King")) 12 heros.remove(hero); 13 } 14 }
否则就会报这样的异常
如果要在遍历的过程中删除元素,可以使用迭代器方式:
2)LinkedList
LinkedList和ArrayList一样,也实现了List接口。那些常用方法不再赘述,同时还实现了双向链表结构Deque接口,可以很方便的在头尾插入数据。
它的底层数据结构是链表,查询慢,增删快;线程不安全,效率高。
什么是链表结构?
一种线性的存储结构,将要存储的数据存在存储单元中,这个单元除了数据外,还存储了下个存储单元的地址(有些还会存放上个存储单元的地址),每次查找数据的时候,通过这个地址去找到下一个存储单元。
双向链表的话,不仅每个存储单元有指向上一个和下一个单元的地址,链表的尾结点和头结点也是相连的。
注意,LinkedList中的元素:
1.允许为空
2.允许重复
3.有序
4.线程不安全
5.遍历时使用foreach速度远高于for循环

1 public class LinkedListDemo { 2 public static void main(String[] args) { 3 LinkedList<Hero> heros = new LinkedList<>(); 4 heros.addFirst(new Hero("兔头披风侠")); 5 heros.addFirst(new Hero("魔鬼改造人")); 6 heros.addLast(new Hero("King")); 7 System.out.println(heros); 8 //查看头元素 9 System.out.println(heros.getFirst()); 10 //查看尾元素 11 System.out.println(heros.getLast()); 12 } 13 }
除了上述两种接口以外,LinkedList还实现了Queue接口,是一种先进先出的数据结构。
常用方法:
peek():查看第一个元素
poll():取出第一个元素,该元素会在队列中被删除
offer():在队列最后添加元素

1 Queue<Hero> que = new LinkedList<>(); 2 que.offer(new Hero("秃头披风侠")); 3 que.offer(new Hero("魔鬼改造人")); 4 que.offer(new Hero("King")); 5 System.out.println(que); 6 System.out.println("查看第一个元素"); 7 System.out.println(que.peek()); 8 System.out.println("取出所有元素"); 9 while(que.size()>0) 10 System.out.println(que.poll()); 11 System.out.println(que);
使用LinkedList模拟栈

1 class LinkedStack<E> { 2 LinkedList<E> list; 3 public LinkedStack(){ 4 list = new LinkedList<E>(); 5 } 6 7 public void push(E ele) { 8 list.addFirst(ele); 9 } 10 11 public E pop(){ 12 return list.removeFirst(); 13 } 14 15 public E peek(){ 16 return list.getFirst(); 17 } 18 19 public int size(){ 20 return list.size(); 21 } 22 }
3)Vector
List list2 = new Vector();
底层数据结构是数组,查询快,增删慢;线程安全,效率低,几乎已经淘汰了这个集合
四、ArrayList的优缺点
从上面的几个过程总结一下ArrayList的优缺点。ArrayList的优点如下:
1、ArrayList底层以数组实现,是一种随机访问模式,再加上它实现了RandomAccess接口,因此查找也就是get的时候非常快
2、ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已
不过ArrayList的缺点也十分明显:
1、删除元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能
2、插入元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能
因此,ArrayList比较适合顺序添加、随机访问的场景。
五、LinkedList和ArrayList的对比
1、顺序插入速度ArrayList会比较快,因为ArrayList是基于数组实现的,数组是事先new好的,只要往指定位置塞一个数据就好了;LinkedList则不同,每次顺序插入的时候LinkedList将new一个对象出来,如果对象比较大,那么new的时间势必会长一点,再加上一些引用赋值的操作,所以顺序插入LinkedList必然慢于ArrayList
2、基于上一点,因为LinkedList里面不仅维护了待插入的元素,还维护了Entry的前置Entry和后继Entry,如果一个LinkedList中的Entry非常多,那么LinkedList将比ArrayList更耗费一些内存
3、数据遍历的速度,看最后一部分,这里就不细讲了,结论是:使用各自遍历效率最高的方式,ArrayList的遍历效率会比LinkedList的遍历效率高一些
4、有些说法认为LinkedList做插入和删除更快,这种说法其实是不准确的:
(1)LinkedList做插入、删除的时候,慢在寻址,快在只需要改变前后Entry的引用地址
(2)ArrayList做插入、删除的时候,慢在数组元素的批量copy,快在寻址
所以,如果待插入、删除的元素是在数据结构的前半段尤其是非常靠前的位置的时候,LinkedList的效率将大大快过ArrayList,因为ArrayList将批量copy大量的元素;越往后,对于LinkedList来说,因为它是双向链表,所以在第2个元素后面插入一个数据和在倒数第2个元素后面插入一个元素在效率上基本没有差别,但是ArrayList由于要批量copy的元素越来越少,操作速度必然追上乃至超过LinkedList。
从这个分析看出,如果你十分确定你插入、删除的元素是在前半段,那么就使用LinkedList;如果你十分确定你删除、删除的元素在比较靠后的位置,那么可以考虑使用ArrayList。如果你不能确定你要做的插入、删除是在哪儿呢?那还是建议你使用LinkedList吧,因为一来LinkedList整体插入、删除的执行效率比较稳定,没有ArrayList这种越往后越快的情况;二来插入元素的时候,弄得不好ArrayList就要进行一次扩容,记住,ArrayList底层数组扩容是一个既消耗时间又消耗空间的操作