java集合类源码分析之List

Posted Wilange

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java集合类源码分析之List相关的知识,希望对你有一定的参考价值。

这一节主要介绍List接口的几个实现类的区别:

1.线程安全

 Vector是线程安全的,而ArrayList和LinkedList是非线程安全的。从源码中我们可知,Vector类中的方法大部分都是同步的,即被synchronized关键字修饰;而那些没有被synchronized关键字修饰的方法都是通过调用其他同步方法或者采用同步代码块来达到同步的。

技术分享
 1     public synchronized void addElement(E obj) {
 2         modCount++;
 3         ensureCapacityHelper(elementCount + 1);
 4         elementData[elementCount++] = obj;
 5     }
 6 
 7     public synchronized boolean removeElement(Object obj) {
 8         modCount++;
 9         int i = indexOf(obj);
10         if (i >= 0) {
11             removeElementAt(i);
12             return true;
13         }
14         return false;
15     }
16 
17     public synchronized E get(int index) {
18         if (index >= elementCount)
19             throw new ArrayIndexOutOfBoundsException(index);
20 
21         return elementData(index);
22     }
23 
24     public synchronized void insertElementAt(E obj, int index) {
25         modCount++;
26         if (index > elementCount) {
27             throw new ArrayIndexOutOfBoundsException(index
28                                                      + " > " + elementCount);
29         }
30         ensureCapacityHelper(elementCount + 1);
31         System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
32         elementData[index] = obj;
33         elementCount++;
34     }
View Code
技术分享
 1     public boolean contains(Object o) {
 2         return indexOf(o, 0) >= 0;
 3     }
 4 
 5     public synchronized int indexOf(Object o, int index) {
 6         if (o == null) {
 7             for (int i = index ; i < elementCount ; i++)
 8                 if (elementData[i]==null)
 9                     return i;
10         } else {
11             for (int i = index ; i < elementCount ; i++)
12                 if (o.equals(elementData[i]))
13                     return i;
14         }
15         return -1;
16     }
17 
18     public Enumeration<E> elements() {
19         return new Enumeration<E>() {
20             int count = 0;
21 
22             public boolean hasMoreElements() {
23                 return count < elementCount;
24             }
25 
26             public E nextElement() {
27                 synchronized (Vector.this) {
28                     if (count < elementCount) {
29                         return elementData(count++);
30                     }
31                 }
32                 throw new NoSuchElementException("Vector Enumeration");
33             }
34         };
35     }
View Code

2.适用条件

ArrayList:适用于随机访问比较频繁(自带索引),而插入和删除操作较少的情况下;

LinkedList:适用于插入和删除比较频繁(修改前后节点),而随机访问较少的情况下;

Vector:适用于要求线程安全(方法同步),执行效率不高,数据量大的情况下。

3.内存消耗

在内存消耗方面,LinkedList < ArrayList < Vector。

LinkedList由于采用链表的形式实现,所以不需要指定容量大小,因此内存消耗较少;而ArrayList和Vector都是采用数组的形式实现,需要指定初始容量的大小(默认都是10),并且当容量不够时都需要进行扩容,在扩容方面:

  • ArrayList每次只增加当前数组长度的一半,即newCapacity = oldCapacity + (oldCapacity >> 1),源码中扩容的方法如下:
技术分享
 1     private void grow(int minCapacity) {
 2         // overflow-conscious code
 3         int oldCapacity = elementData.length;
 4         int newCapacity = oldCapacity + (oldCapacity >> 1);
 5         if (newCapacity - minCapacity < 0)
 6             newCapacity = minCapacity;
 7         if (newCapacity - MAX_ARRAY_SIZE > 0)
 8             newCapacity = hugeCapacity(minCapacity);
 9         // minCapacity is usually close to size, so this is a win:
10         elementData = Arrays.copyOf(elementData, newCapacity);
11     }
View Code
  • Vector每次增加当前数组长度的一倍,即newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity),capacityIncrement是人为指定的扩容大小,默认为0,源码中扩容的方法如下:
技术分享
 1     private void grow(int minCapacity) {
 2         // overflow-conscious code
 3         int oldCapacity = elementData.length;
 4         int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
 5                                          capacityIncrement : oldCapacity);
 6         if (newCapacity - minCapacity < 0)
 7             newCapacity = minCapacity;
 8         if (newCapacity - MAX_ARRAY_SIZE > 0)
 9             newCapacity = hugeCapacity(minCapacity);
10         elementData = Arrays.copyOf(elementData, newCapacity);
11     }
View Code

综上所述,Vector对内存的消耗比较高,其次是ArrayList。

4.集合排序

 有了数据的存储方法(集合),当然要考虑到数据在集合中的顺序问题,下面对集合排序做一个简单的总结:

  • 集合中的排序通常调用Collections类中的静态方法来实现,常用的方法有:sort、reverse、shuffle、min、max等。
技术分享
 1         LinkedList<Integer> linkedList = new LinkedList<Integer>();
 2         linkedList.add(100);
 3         linkedList.add(120);
 4         linkedList.add(110);
 5         Collections.sort(linkedList);//升序排列
 6         System.out.println(linkedList);
 7         
 8         Collections.sort(linkedList, new Comparator<Integer>() {
 9 
10             @Override
11             public int compare(Integer o1, Integer o2) {
12                 // TODO Auto-generated method stub
13 //                return 0;
14                 return o2.compareTo(o1);    //降序排列
15             }
16         });
17         System.out.println(linkedList);
18         
19         Collections.shuffle(linkedList);//随机乱序
20         System.out.println(linkedList);
21         
22         Collections.reverse(linkedList);//逆序
23         System.out.println(linkedList);
24         
25         System.out.println(Collections.min(linkedList));//最小值
26         System.out.println(Collections.max(linkedList));//最大值
View Code

这里只给出了LinkedList的排序代码,而对于ArrayList和Vector的排序也是同样的操作,此处不再赘述。

 

以上是关于java集合类源码分析之List的主要内容,如果未能解决你的问题,请参考以下文章

Java 容器源码分析之 Map

java集合类源码分析之Map

jdk源码分析之List--常用实现类分析与对比

Java集合源码分析之LinkedList

java集合之ArrayList源码分析

Java之set源码分析