又有一位工作2年的小伙伴面试的时候,被问到一个集合相关的问题。说请你谈谈ArrayList、Vector和LinkedList 的存储性能及特性。
今天呢,我给大家分享一下我对这个问题的理解。
1、存储性能及特性
关于ArrayList、Vector和LinkedList 的存性能理及特性,我从以下3个方面来分析:
(1)首先,ArrayList 和 Vector 的底层都是采用数组的来存储数据,而且都是根据索引来取数据,这样设计使得获取数据快而插入数据慢。另外,每次扩容都要移动数组中的元素,存储数据量较大的时候会影响读写性能。
(2)其次,由于Vector 中的方法都使用了 synchronized 修饰,因此 ,Vector 中对数据操作都是线程安全的,但性能上比ArrayList 差。
(3)然后,LinkedList 的底层是采用双向链表来存储数据的,也就是说将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,内存的利用率更高。LinkedList获取数据需要根据索引序号,向前或者向后遍历,但是插入数据时只需要记录本项的前后项即可,所以,LinkedList插入数据的速度更快。
(4)最后,再补充一点,Vector是Java 早期的版本中提供的容器, 属于遗留容器,官方已经不再推荐使用。但是由于 ArrayList 和 LinkedListed 都是非线程安全的,在多线程环境下,可以使用工具类Collections 的 synchronizedList() 方法,将容器转换成线程安全的容器再使用。这其实也是装饰器模式的一种应用。
2、关于遗留容器
关于Java中的遗留容器,我最后再补充一下。除Vector之外,还有Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器,这些容器中,Properties 类存在比较严重的设计缺陷。来看这段源码:
/* Since : JDK1.0 See Also : native2ascii tool for Solaris, native2ascii tool for Windows Author : Arthur van Hoff, Michael McCloskey, Xueming Shen */ public class Properties extends Hashtable<Object,Object> { }
Properties是一个键和值都是字符串的特殊的键值对映射,在设计上应该是关联一个Hashtable,并将它的两个泛型参数设置为 String 类型,但是 Java API 中的Properties是直接继承了 Hashtable,这很明显是对继承的滥用。主要体现在以下两个方面:
(1)首先,根据合成复用原则,这里Properties 和Hashtable的代码复用关系应该是 Has-A 关系,而不是 Is-A 关系。
(2)另一方面,这两个容器都属于工具类,继承工具类本身就是一个错误的做法,使用工具类最好的方式是 Has-A 关系(关联)或Use-A 关系(依赖)。
既然都讲到这里了,最后再扩展一下Stack 类在设计上也存在Properties同样的缺陷。来看这样一段源码:
/* Since : JDK1.0 Author : Jonathan Payne */ public class Stack<E> extends Vector<E> { }
在JDK的util包中,我们发现Stack类也是继承了 Vector,这个设计也是不太合理的。
好了,以上就是我对ArrayList、Vector和LinkedList的理解。