java集合:ArrayList

Posted

tags:

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

一、简介。(1.8源码)

  ArrayList是实现List接口的动态数组。(动态意思就是大小可变)默认初始容量为10。随着ArrayList中元素的增加,它的容量也会不断的自动增长。如果我们知道具体所需数据量,在构造ArrayList时可以给ArrayList指定一个初始容量,避免内存的浪费。

二、源码。

  (1)三个构造方法。

  第一个:用于初始化列表的容量。

技术分享

  第二个:默认构造函数,初始容量为10的空列表

技术分享

  第三个:构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的

技术分享

  (2)新增元素的四种方法

  第一个:将指定的元素添加到此列表的尾部,里边含有ensureCapacity()方法能自动检查是否需要扩容的。

  技术分享

  第二个:将指定的元素插入此列表中的指定位置,。

  技术分享

  其中这个方法是用于检查索引位置是否正确。

 技术分享

  第三个:按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。

  public static void arraycopy(Object src, int srcPos,Object dest,int destPos,int length)  src:源数组;srcPos:源数组要复制的起始位置;dest:目的数组;destPos:目的数组放置的起始位置;length:复制的长度。

1     public boolean addAll(Collection<? extends E> c) {
2         Object[] a = c.toArray();
3         int numNew = a.length;
4         ensureCapacityInternal(size + numNew);  // Increments modCount
5         System.arraycopy(a, 0, elementData, size, numNew);
6         size += numNew;
7         return numNew != 0;
8     }

  第四个:从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。

 1     public boolean addAll(int index, Collection<? extends E> c) {
 2         rangeCheckForAdd(index);
 3 
 4         Object[] a = c.toArray();
 5         int numNew = a.length;
 6         ensureCapacityInternal(size + numNew);  // Increments modCount
 7 
 8         int numMoved = size - index;
 9         if (numMoved > 0)
10             System.arraycopy(elementData, index, elementData, index + numNew,
11                              numMoved);
12 
13         System.arraycopy(a, 0, elementData, index, numNew);
14         size += numNew;
15         return numNew != 0;
16     }

  (3)删除元素的五种方法

  第一种:根据下标删除元素

 1     public E remove(int index) {
 2         rangeCheck(index);
 3 
 4         modCount++;
 5         E oldValue = elementData(index);
 6 
 7         int numMoved = size - index - 1;
 8         if (numMoved > 0)
 9             System.arraycopy(elementData, index+1, elementData, index,
10                              numMoved);
11         elementData[--size] = null; // clear to let GC do its work
12 
13         return oldValue;
14     }

  第二种:删除匹配到最近的元素。注意“==”与“equals”的区别,“==”比较的是对象的引用,“equals”比较的是对象的值。什么时候应该用什么,自己看内存的存储规则。

 1     public boolean remove(Object o) {
 2         if (o == null) {
 3             for (int index = 0; index < size; index++)
 4                 if (elementData[index] == null) {
 5                     fastRemove(index);
 6                     return true;
 7                 }
 8         } else {
 9             for (int index = 0; index < size; index++)
10                 if (o.equals(elementData[index])) {
11                     fastRemove(index);
12                     return true;
13                 }
14         }
15         return false;
16     }

  第三种:与一类似不做解释

1     private void fastRemove(int index) {
2         modCount++;
3         int numMoved = size - index - 1;
4         if (numMoved > 0)
5             System.arraycopy(elementData, index+1, elementData, index,
6                              numMoved);
7         elementData[--size] = null; // clear to let GC do its work
8     }

  第四种:删除指定范围内的一段元素

 1     protected void removeRange(int fromIndex, int toIndex) {
 2         modCount++;
 3         int numMoved = size - toIndex;
 4         System.arraycopy(elementData, toIndex, elementData, fromIndex,
 5                          numMoved);
 6 
 7         // clear to let GC do its work
 8         int newSize = size - (toIndex-fromIndex);
 9         for (int i = newSize; i < size; i++) {
10             elementData[i] = null;
11         }
12         size = newSize;
13     }

  第五种:原集合与给定集合比较。如果原集合与给定的集合无相同元素则原集合不改变,反之。

1     public boolean removeAll(Collection<?> c) {
2         Objects.requireNonNull(c);
3         return batchRemove(c, false);
4     }
 1     private boolean batchRemove(Collection<?> c, boolean complement) {
 2         final Object[] elementData = this.elementData;
 3         int r = 0, w = 0;
 4         boolean modified = false;
 5         try {
 6             for (; r < size; r++)
 7                 if (c.contains(elementData[r]) == complement)
 8                     elementData[w++] = elementData[r];
 9         } finally {
10             // Preserve behavioral compatibility with AbstractCollection,
11             // even if c.contains() throws.
12             if (r != size) {
13                 System.arraycopy(elementData, r,
14                                  elementData, w,
15                                  size - r);
16                 w += size - r;
17             }
18             if (w != size) {
19                 // clear to let GC do its work
20                 for (int i = w; i < size; i++)
21                     elementData[i] = null;
22                 modCount += size - w;
23                 size = w;
24                 modified = true;
25             }
26         }
27         return modified;
28     }

   (4)替换元素方法

1     public E set(int index, E element) {
2         rangeCheck(index);
3 
4         E oldValue = elementData(index);
5         elementData[index] = element;
6         return oldValue;
7     }

  (5)查找元素方法

1     public E get(int index) {
2         rangeCheck(index);
3 
4         return elementData(index);
5     }

  (6)关于源码扩容操作,1.8的乱。

1.8

 1 private void ensureCapacityInternal(int minCapacity) {
 2     if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
 3         minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
 4     }
 5 
 6     ensureExplicitCapacity(minCapacity);
 7 }
 8 private void ensureExplicitCapacity(int minCapacity) {
 9     modCount++;
10 
11     // overflow-conscious code
12     if (minCapacity - elementData.length > 0)
13         grow(minCapacity);
14 }
15 private void grow(int minCapacity) {
16     // overflow-conscious code
17     int oldCapacity = elementData.length;
18     int newCapacity = oldCapacity + (oldCapacity >> 1);
19     if (newCapacity - minCapacity < 0)
20         newCapacity = minCapacity;
21     if (newCapacity - MAX_ARRAY_SIZE > 0)
22         newCapacity = hugeCapacity(minCapacity);
23     // minCapacity is usually close to size, so this is a win:
24     elementData = Arrays.copyOf(elementData, newCapacity);
25 }
26 private static int hugeCapacity(int minCapacity) {
27     if (minCapacity < 0) // overflow
28         throw new OutOfMemoryError();
29     return (minCapacity > MAX_ARRAY_SIZE) ?
30         Integer.MAX_VALUE :
31         MAX_ARRAY_SIZE;
32 }

从别人博客弄来简短的

为什么每次扩容处理会是1.5倍,而不是2.5、3、4倍呢?通过google查找,发现1.5倍的扩容是最好的倍数。因为一次性扩容太大(例如2.5倍)可能会浪费更多的内存(1.5倍最多浪费33%,而2.5被最多会浪费60%,3.5倍则会浪费71%……)。但是一次性扩容太小,需要多次对数组重新分配内存,对性能消耗比较严重。所以1.5倍刚刚好,既能满足性能需求,也不会造成很大的内存消耗。

 

技术分享

 


以上是关于java集合:ArrayList的主要内容,如果未能解决你的问题,请参考以下文章

在java中怎样求多个arraylist集合的交集?

java集合 ArrayList问题

Java 集合学习笔记:ArrayList

Java 集合学习笔记:ArrayList

JAVA——底层源码阅读——集合ArrayList的实现底层源码分析

Java知识树 集合 ArrayList