1.相同点
Arraylist,LinkedList和Vector都是List集合的实现类,其相同点也是List集合的特点,换而言之,其特点可以总结为
他们都是有序的,元素可重复的集合.有序指的是元素的存入与输出的顺序一致,也就是先进先出;
2.不同点
(1)Arraylist
ArrayList底层使用的是Java数组来存储集合中的内容,这个数组是Object类型的:
- transient Object[] elementData;
这里所定义的elementData只能在包内调用,代表的是其中的元素
定义的size表示数组的长度:
- private int size;
Arraylist代码中有个常量,表示数组的默认容量,大小为10:
- /**
- * Default initial capacity.
- */
- private static final
当我们在给ArrayList 放入元素时,ArrayList 数组的大小会自动对数组进行扩容具体过程如下
- //添加元素
- //添加元素
- public boolean add(E e) {
- ensureCapacityInternal(size + 1); // Increments modCount!!
- elementData[size++] = e;
- return true;
- }
- }
在这里我们可以使用一下反射来查看Arraylist的数组长度
- static void print (List arraylist) throws Exception {
- //得到类的对象
- Class c = arraylist.getClass();
- //获得属性值
- Filed f = c.getDeclaredField(“elementData”);
- //设置为可以访问的属性
- f.setAccessible(true);
- Object [] o =(Object [])f.get(arraylist);
- System.out.println(o.length);
- }
我们调用这个方法就可以得到Arraylist数组的长度
我们也可以查看Arraylist的源代码中增加的后续方法
private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容长度0.5倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity);//数组扩容 } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
Arraylist每次扩容后,长度都是原来的1.5倍。
简单来说,ArrayLis是实现了基于动态数组的数据结构,由于使用索引从指定的位置(用index)检索一个对象,他的查询效率很高,由于在非末尾插入和删除时需要重新移动数据,所以他的删除或者插入的效率比较低。每次自增0.5倍容量
(2)Vector
我们可以看看Vector的源代码,这时我们会发现,Vector的构造方法和Arraylist的基本一致,但是Vector与Arraylist存在了一个最大的差异,可以从add()方法看出
- //Vector
- public synchronized boolean add(E e) {
- modCount++;
- ensureCapacityHelper(elementCount + 1);
- elementData[elementCount++] = e;
- return true;
- }
- //ArrayList
- public boolean add(E e) {
- ensureCapacityInternal(size + 1); // Increments modCount!!
- elementData[size++] = e;
- return true;
- }
相对于Arraylist,Vector是上了锁的,这使得Vector的线程是安全的,但是这也会导致Vector的效率比Arraylist要低.
我们可以在看一下Vector增加后的方法
- private void grow(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
- capacityIncrement : oldCapacity);
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
- }
可以发现,Vector每次改变容量都是以原容量的1倍进行增长的.
综上所述,Vector可以当成是一个安全的Arraylist来使用,不过效率比Arraylist要低;
(3)LinkedList
LinkedList可以直译为链表,顾名思义LinkedList一定是和链表脱不开关系的
在API中对LinkedList是这样描述的:List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。
事实上LinkedList是一个双向的链表,那么他肯定会具备链表的特点
在插入、删除集合中任何位置的元素所花费的时间都是一样的,但它在索引一个元素的时候比较慢。
- transient Node<E> first;
- transient Node<E> last;
- public boolean add(E e) {
- linkLast(e);
- return true;
- }
- void linkLast(E e) {
- final Node<E> l = last;
- final Node<E> newNode = new Node<>(l, e, null);
- last = newNode;
- if (l == null)
- first = newNode;
- else
- l.next = newNode;
- size++;
- modCount++;
- }
- public E get(int index) {
- checkElementIndex(index);
- return node(index).item;
- }
由此我们可以总结出LinkedList的特点:LinkedLis是实现了基于双链表的数据结构,在插入、删除集合中任何位置的元素所花费的时间都是一样的,但它在索引一个元素的时候比较慢。
还有一点,由于LinkedList实现了 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。我们也可以用LinkedList来模拟队列和栈。