集合(2)——List集合

一、概念

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 }
View Code

 

有一点需要注意的是,在遍历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    }     
View Code

否则就会报这样的异常

 

 

 如果要在遍历的过程中删除元素,可以使用迭代器方式:

 

 

 

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 }
View Code

 

除了上述两种接口以外,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);
View Code

 

使用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 }
View Code

 

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底层数组扩容是一个既消耗时间又消耗空间的操作

 

posted on 2019-10-05 12:04  nameless_vi  阅读(177)  评论(0编辑  收藏  举报

导航