ArrayList,LinkedList和Vector都继承自List接口。ArrayList和Vector的底层是动态数组,LinkedList的底层是双向链表.
ArrayList,LinkedList的区别:
通过上图,我们看出数组是通过索引进行操作,数组分配的是一块连续的内存空间,只要拿到对应的索引就能拿到数据,例:拿到1就能得到A2,当然在A2后面插入数据,就需要移动后面的所有数据;而链表不一样,数据的地址是在前一个链表中,例:要得到A2就必须得到A1,再得到索引B1,得到B1才能得到A2的地址,插入数据则只需要在数据的前后更改索引便可插入(图b2),因此,数组是查询块,插入删除慢,而链表查询慢,插入删除块。
ArrayList是用数组进行存储,LinkedList是以链表的形式存储的,LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
面试题:
为什么ArrayList都用for循环遍历,不用iterator迭代器遍历,而LinkedList都用iterator遍历,极少用for遍历?
从继承的接口来看,ArrayList继承了一个RandomAccess(随机访问),这是一个空的接口,但是作用却很大,看一个工具类Collections的binarySearch方法源码:
从中可以看出,会对list进行判断,是否继承了RandomAccess,如果继承了用for循环,如果没有用iterator遍历。
ArrayList、和Vector的区别
从ArrayList跟Vector的创建来看,两个类继承的都一样,实现的方法体也一样:
ArrayList类:
Vector类:
从方法上来看(以addAll方法举例,其他方法一样):
ArrayList方法:
Vector方法:
ArrayList方法没有synchronized,而Vector方法进行了修饰,也就是说Vector是线程安全的,它的方法之间是线程同步的,且Vector是很早就推出的一个类,安全性高,而ArrayList是线程序不安全的,它的方法之间是线程不同步的。
从空间的增长方式来看:
JDK1.8的源码中,无参构造器的注释写的很清楚,会创建一个初始容量为10的数组,但是在构造器中并没有体现出来。这是因为从JDK1.7开始,调用无参构造时,只会创建一个空数组。只有调用add()或addAll()方法时,才会初始化数组的容量。
ArrayList方法:
其中ensureCapacityInternal()
从前面的分析我们可以知道,当我们使用无参构造器或是指定初始容量为0时创建的集合,会创建一个空数组,且这个空数组就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,此时我们方法的入参minCapacity为1,而DEFAULT_CAPACITY就是默认的数组初始化容量10。
当数组最小所需容量大于当前数组的容量时,就会调用grow()方法来对数组进行扩容。
oldCapacity为扩容前数组的长度,newCapacity是在原数组长度的基础上,加上了(oldCapacity >> 1),右移一位相当于除以2,即newCapacity = oldCapacity + 0.5oldCapacity 。也就是说容量扩大为了原来的1.5倍。
在vector的grew方法中:
从画红线的代码可以看出,如果指定了大小且大于0,就扩容指定的大小,如果没有指定,就两个capacityIncrement相加,即扩容至两倍的大小 。
欢迎留言讨论。