疯狂Java讲义读书笔记08 Java集合-02List

List集合

List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素可以通过索引来访问指定位置的集合元素。

List作为Collection接口的子接口,当然可以使用Collection接口里的全部方法。而且由于List是有序集合,因此List集合里增加了一些根据索引来操作集合元素的方法。

 

 当调用List的set(int index,Object element)方法来改变List集合指定索引处的元素时,指定的索引必须是List集合的有效索引。例如集合长度是4,就不能指定替换索引为4的元素。也就是说set(int index,Object element)方法不会改变List集合的长度

 

Java8为List集合增加了sort和replaceAll两个常用的默认方法,其中sort()方法需要一个Comparator对象来控制元素排序,程序可使用Lambda表达式来作为参数。而replaceAll方法则需要一个UnaryOperator来替换所有的集合元素,UnaryOperator也是一个函数式接口,因此程序也可以使用Lambda表达式作为参数。如下:

 

 

与Set只提供了一个iterator方法不同,List还额外提供了一个listIterator方法,该方法返回了一个ListIterator对象,ListIterator接口继承了Iterator接口,提供了专门操作list的方法。ListIterator接口在Iterator接口的基础上增加了如下方法。

 

 对比普通的iterator发现,ListIterator增加了向前迭代的功能(Iterator只能向后迭代)而ListIterator还可以通过add方法向List集合中添加元素(Iterator只能删除元素)

 

ArrayList和Vector实现类

ArrayList和Vector作为List类的两个典型实现,完全支持前面介绍的List接口的全部功能

ArrayList和Vector都是基于数组实现的List类,所以ArrayList和Vector类封装了一个动态的、允许再分配的Object[]数组。

使用initialCapacity参数来设置该数组的长度,当向ArrayList和Vector中添加元素超出了数组的长度时,它们的initialCapacity会自动增加。

 

对于通常的编程场景,程序员无须关心ArrayList和Vector的initialCapacity。但是有大量元素需要添加的时候,可以使用ensureCapacity(int minCapacity)这可以减少重分配的次数,提高性能。

如果开始就知道ArrayList或Vector集合需要保存多少个元素,则可以在创建它们时就指定initialCapacity大小。如果创建空的ArrayList或Vector集合时不指定initialCapacity参数,则默认长度是10

此外,ArrayList和Vector还提供了如下两个方法来重新分配Object数组

 

 ArrayList和Vector在用法上几乎完全相同,但是由于Vector是一个古老的集合,那时候Java还没有提供系统的集合框架,所以里面有一些很长的方法名

除此之外,ArrayList与Vector显著的区别就是ArrayList是线程不安全的,必须手动保证该集合的同步性。但Vector是线程安全的,所以性能比ArrayList的性能地。

实际上即使需要线程安全的List我们也不推荐Vector。后面会介绍Collections工具类,它可以将一个ArrayList变成线程安全的。

 

Vector还提供了一个Stack子类,它用于模拟栈这种数据结构,栈指的是后进先出push进栈,pop出栈。

与其他集合一样,进栈出栈都是Object,因此栈中取出的运算需要进行类型转换,除非你只是使用Object具有的操作

Stack提供了如下几个方法

 

 

需要指出的是,由于Stack继承了Vector,因此它也是一个非常古老的Java集合类,它同样是线程安全、性能较差的,因此应该尽量少用。

如果程序需要使用栈这种数据结构,可以考虑使用后面将要介绍的ArrayDeque

 

ArrayDeque也是List的实现类,ArrayDeque既实现了Deque接口,也实现了List接口,由于实现了Deque,因此可以当作栈来使用,底层也是基于数组实现的。

 

 

固定长度的List

前面讲数组时介绍了一个操作数组的工具类:Arrays,该工具提供了asList(Object ... a)方法

该方法可以将一个数组或指定个数的对象转换成一个List集合,这个集合既不是ArrayList实现类也不是Vector的实例,而是Arrays内部类的ArrayList的实例

 

Arrays.ArrayList是一个固定长度的List集合,程序只能遍历访问该集合的元素,不能增加、删除该集合的元素

 

 

Queue集合

Queue用于模拟队列这种数据结构,队列通常是指先进先出的容器。

 

 Queue接口有一个PriorityQueue实现类。初次之外,Queue还有一个Deque接口,Deque代表一个双端队列。

双端队列可以同时从两端进行添加删除元素,因此Deque的实现类即可以当成队列使用,也可以当成栈来使用

Java为Deque提供了ArrayDeque和LinkedList两个实现类。

 

PriorityQueue实现类

这是一个比较标准的队列实现类,之所以说他是比较标准的队列实现,而不是绝对标准的队列实现。是因为PriorityQueue保存队列元素的顺序并不是按加入队列的顺序,而是按照队列元素的大小重新排序。

因此当调用peek方法或者poll方法取出队列中的元素时,并不是取出最先进入队列的元素,而是取出队列中最小的元素。

从这个意义上来看,PriorityQueue已经违反了队列的最基本规则:先进先出。

 

 PriorityQueue不允许插入null元素,它还需要对队列元素进行排序,PriorityQueue的元素有两种排序方式

1、自然排序,集合中的元素必须实现了Comparable接口

2、定制排序,创建队列时,传入一个Comparator对象,该对象负责对队列中所有的元素进行排序。

 

Deque接口与ArrayDeque实现类

Deque接口是Queue接口的子接口,它代表一个双端队列。

 

 从上面的方法可以看出,Deque不仅可以当成双端队列使用,而且可以当成栈来使用,因为该类里还包含了pop出战和push入栈的两个方法。

 

 

Deque接口提供了一个典型的实现类:ArrayDeque,从该名称就可以看出它是一个基于数组实现的双端队列,创建Deque时同样可以指定一个numElements参数,该参数用于指定Object数组的长度,如果不指定则为16.

下面示范以下当成栈来使用

 

 下面是作为队列使用

 

 

Linked List实现类

LinkedList既实现了List接口也实现了Deque接口,因此即可以当成栈也可以当初队列

 

 LinkedList内部以链表的形式来保存集合中的元素,因此随机访问集合元素时性能较差,但是插入删除元素的性能比较出色。

 

posted @ 2020-02-03 20:42  chyblogs  阅读(134)  评论(0)    收藏  举报