常用的Java集合包括List,Map,Set接口,其常用的实现类包括:ArrayList,Vector,LinkedList,HashMap,HashTable,LinkedHashMap,TreeMap,HashSet,LinkedHashSet,TreeSet等。
1、基于数组的List:
ArrayList和Vector都是基于数组的List实现类,其中ArrayList是非线程安全的,而Vector对大部分方法做了线程同步,二者使用上没有太明显的性能差异。其常用操作:
add,add(index),remove
实际上是对底层的数组封装的操作。
对ArrayList而言,其默认的数组初始化大小为10,当数组容量不足时,会以原数组大小的1.5倍进行扩展,数组扩展使用了Arrays.copyOf(),内存拷贝,当频繁进行数组扩容时,会对性能有很大影响,因此在创建时对默认大小进行合理预估,分配,可以减少扩容次数,提高性能。
由于使用数组,一段连续的内存空间,其访问效率是很高的,而对内容修改时相对会较慢,因为要对原有数组内容进行重排。
add(),add(int index),remove(int index)
在List尾部新增数据,十分高效,而在指定位置插入数据时会对该位置以后的所有数据进行重排,其性能会大打折扣。对remove()而言也是一样,当某个位置元素被修改以后,其后面的元素都要重拍,进行数组拷贝,耗费更多内存。
2、基于链表的List:
相比于基于数组的List实现,LinkedList是一个双向循环链表,其插入操作,在任意位置插入操作都是相当高效的,但其删除操作由于需要遍历链表来寻找要删除的元素,尽管其实现采用了分从前往后,从后往前的两种查询方式,减少了一半的查询量,但对于中部的数据,其查询速度是较慢的。
3、迭代方式:
对于遍历而言,基于数组的List实现,支持随机访问,速度十分高效,三种遍历方式:
forEach(), iterator, for()
forEach()优化后与iterator几乎一致,但多了一次额外赋值语句,相比于iterator差一点,for循环的直接随机访问仍然是最高效的。
而LinkedList在随机访问的效率是不可接受的,对于实现未知的List类,可以通过判断RandomAccess接口判断是否支持随机访问,来选择遍历方式。