ArrayList和LinkedList

ArrayList和LinkedList

ArrayList   实现原理:   http://zhangshixi.iteye.com/blog/674856

ArrayList和LinkedList在性能上各有优缺点,都有各自所适用的地方,总的说来可以描述如下: 

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针(遍历链表)。 
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 

1 // 移除此列表中指定位置上的元素。  
 2  public E remove(int index) {  
 3     RangeCheck(index);  
 4   
 5     modCount++;  
 6     E oldValue = (E) elementData[index];  
 7   
 8     int numMoved = size - index - 1;  
 9     if (numMoved > 0)  
10         System.arraycopy(elementData, index+1, elementData, index, numMoved);  
11     elementData[--size] = null; // Let gc do its work  
12   
13     return oldValue;  
14  }
ArrayList的删除操作:首先是检查范围,修改modCount,保留将要被移除的元素,将移除位置之后的元素向前挪动一个位置,将list末尾元素置空(null gc回收),返回被移除的元素。

 // 将指定的元素添加到此列表的尾部。  
public boolean add(E e) {  
30    ensureCapacity(size + 1);   
31    elementData[size++] = e;  
32    return true;  
33 }   
 看到add(E e)中先调用了ensureCapacity(size+1)方法,之后将元素的索引赋给elementData[size],而后size自增。例如初次添加时,size为0,add将elementData[0]赋值为e,然后size设置为1(类似执行以下两条语句elementData[0]=e;size=1)。将元素的索引赋给elementData[size]不是会出现数组越界的情况吗?这里关键就在ensureCapacity(size+1)中了。



4.对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。

5.在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。

6.ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private static class Entry {   
  2.          Object element;   
  3.          Entry next;   
  4.          Entry previous;   
  5.      }   

 
每个Entry对象reference列表中的一个元素,同时还有在LinkedList中它的上一个元素和下一个元素。一个有1000个元素的LinkedList对象将有1000个链接在一起的Entry对象,每个对象都对应于列表中的一个元素。这样的话,在一个LinkedList结构中将有一个很大的空间开销,因为它要存储这1000个Entity对象的相关信息。 
ArrayList使用一个内置的数组来存储元素,这个数组的起始容量是10.当数组需要增长时,新的容量按如下公式获得:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%。这就意味着,如果你有一个包含大量元素的ArrayList对象,那么最终将有很大的空间会被浪费掉,这个浪费是由ArrayList的工作方式本身造成的。如果没有足够的空间来存放新的元素,数组将不得不被重新进行分配以便能够增加新的元素。对数组进行重新分配,将会导致性能急剧下降。如果我们知道一个ArrayList将会有多少个元素,我们可以通过构造方法来指定容量。我们还可以通过trimToSize方法在ArrayList分配完毕之后去掉浪费掉的空间。


ArrayList和LinkedList都是非线程安全的

ArrayList也采用了快速失败(Fail-Fast)的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险

ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类


Vector(线程安全的ArrayList)和Stack(继承于Vector) 则是线程安全的List实现

Vertor底层是基于数组实现的,且其是同步的。但是添加到一定量的元素后,再添加元素其长度会100%扩容(原来的长度10变成20),而ArrayList底层也是基于数组实现的,但其只会小幅扩容(原数组长度*3 除2再加1 (50%+1),更节约空间)







猜你喜欢

转载自blog.csdn.net/simon47/article/details/53574508