本文根据疯狂Java讲义(第3版)整理而成,感谢作者李刚老师

如果觉得内容不错的话,推荐大家买一本阅读,绝对物超所值哦

三、List集合

List集合代表一个元素有序,可重复的集合,集合每个元素都有其对应的索引。List集合默认按元素添加顺序设置元素的索引,例如第一次添加的元素索引为,第二次添加的索引为1……

一、List接口和ListIterator接口

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

  • void add(int index, Object element): 将元素element插入到List集合的index处。
  • boolean addAll(int index, Collection c): 将集合c所包含的元素都插入到List集合的index处。
  • Object get(int index): 返回集合index索引处的元素。
  • int indexOf(Object o): Java在线API中文文档 - 开源中国
  • int lastIndexOf(Object o):
  • Object remove(int index):
  • Object set(int index, Object element):
  • List subList(int fromIndex, int toIndex):

除此之外,Java 8还为List接口添加了两个默认方法,

2.List判断两个对象相等的标准是 只要这两个对象通过equals()方法返回true即可。(目标对象作为equals()方法调用者) 也就是说,当使用list的查找方法(indexOf(Object o) 和 lastIndexOf(Object o))时,List会按照索引遍历集合,用参数对象o与每一个索引位置的元素进行比较,相等并且满足方法的要求则返回索引。当程序试图删除一个对象o时(list.remove(o)),List将会调用该o对象的equals()方法依次与集合元素进行比较,如果返回true,List将会删除该元素。

class A{public boolean equals(){ return true; }}
list.remove(new A());// list总是会删除集合中第一个元素

因为:A类的对象调用equals()方法时总是返回true,和集合中任何一个元素比较都返回true,而集合从第一个元素开始比较,所以总是删除第一个元素。

3.Java 8为List集合增加了sort()和replaceAll()两个常用的默认方法。其中sort()方法需要一个Comparator对象(是一个函数式接口)来控制元素排序;而replaceAll()方法则需要一个UnaryOperator来替换所有集合元素,UnaryOperator也是一个函数式接口,因此可以用Lambda表达式来作为参数。本文不做深入介绍,感兴趣的可以参考李刚老师的书。

4.ListIterator接口接口继承了Iterator接口,提供了专门操作List集合的方法。ListIterator接口在Iterator接口的基础上增加了如下方法:

  • boolean hasPrevious(): 还不会查看API文档的同学可以在底下评论哦!
  • Object previous():
  • void add(Object o):

二、ArrayList和Vector

1.ArrayList和Vector是List的典型实现,完全支持List接口的全部功能。二者都封装了一个动态的,允许再分配的Object[]数组,是基于数组实现的List类。如果添加元素超出了该数组的长度时,它们的initialCapacity(初始容量)会自动增加。

2.增加的规则由方法void ensureCapacity(int minCapacity)决定:将数组长度增加大于或等于minCapacity值。因为如果长度增加后还不够的话,还要继续增加。如果集合一次性增加过多元素,可以使用该方法适当调整该值,减少数组重分配次数,增加性能。

3.如果开始就知道ArrayList或Vector需要保存多少元素,则可以在创建时就指定intialCapacity大小。创建空的ArrayList或Vector集合时不指定initialCapacity参数,则Object[]数组的长度默认为10。

4.ArrayList和Vector在用法上几乎完全相同,但由于Vector是一个古老的集合。二者的显著区别是:前者是线程不安全的,后者在是线程安全的。因为Vector对于线程同步功能实现的机制不好,所以Vector性能比较差。而且我们可以很容易地通过Collections工具类保证ArrayList线程安全,所以不建议使用Vector。

5.Vector还提供一个子类Stack,模拟“栈”这种数据结构,后进先出。Stack继承自Vector,比较古老,性能也比较差。不建议使用Stack。 如果需要使用栈这种数据结构,我们可以使用之后介绍的ArrayDeque。

三、LinkedList实现类

1.LinkedList是List接口的实现类,意味着它是一个List集合,可以根据索引来访问元素。另外,LinkedList还实现了Deque接口,可以被当作双端队列,既可以当作“栈”来使用,也可以当作队列使用。

2.ArrayList内部使用数组来保存元素,随机访问集合元素(根据索引)是有很好的性能;而LinkedList内部以链表的形式来保存元素,因此根据索引随机访问时的性能较差,但是在插入、删除元素时性能比较出色。

四、固定长度的List

1.数组有一个工具类:Arrays。该工具类提供了一个asList(Object… a)方法,该方法可以把一个数组或指定个数的对象转换成一个List集合,这个List集合既不是ArrayList实现类的实例,也不是Vector实现类的实例,而是Arrays的内部类ArrayList(Arrays$ArrayList)的实例。

2.该实例是一个固定长度的List集合,只能访问,不可增加、删除该集合中的元素,否则会引发UnsupportedOperationException异常。


参考资料:
1. [疯狂Java讲义(第3版) - 李刚
3. Java 8 API英文文档 - Oracle