Java集合-ArrayList
一直要總結java集合中的知識,不知道應該如何下筆。覺得集合太多東西了,寫細了太難了,寫粗了又感覺寫不好。不管如何覺得還是要堅持的寫一寫基礎這一類的東西,為了提高自己的編程基礎。本來覺的自己對這些已經很熟悉,最近見過一些大神後發現差距太大了,瞬間懵了,只能在加強學習了。
一、ArrayList是什麼?ArrayList是實現List介面的動態數組,所謂動態是指它的大小是可變的。實現了所有可選列表操作,並允許包括 null 在內的所有元素。除了實現 List 介面外,此類還提供一些方法來操作內部用來存儲列表的數組的大小。
既然是數組,肯定就有容量。每個ArrayList對象都有一個容量,該容量是用來表示可以存放多少個數據在裡面,即是數組的大小(默認是10)。當然,動態的肯定就會自動增加,每次我們往裡面添加數據的時候,它都會進行擴容檢查,檢查完擴容會擴大為原來的1.5倍,擴容操作帶來數據向新數組的重新拷貝,影響性能,所以如果我們知道具體業務數據量,在構造ArrayList時可以給ArrayList指定一個初始容量,這樣就會減少擴容時數據的拷貝問題。當然在添加大量元素前,應用程序也可以使用ensureCapacity操作來增加ArrayList實例的容量,這可以減少遞增式再分配的數量。
ArrayList的底層實現是不同步,多線程操作會出現問題,這一點大家要注意。可以插入重複數據,可以插入Null。
二、ArrayList源碼分析2.1、ArrayList定義
public class ArrayList ArrayList的定義,繼承AbstractList,實現List 2.2、底層使用數組
implements List
private static final long serialVersionUID = 8683452581122892189L;//serialVersionUID作用是序列化時保持版本的兼容性,即在版本升級時反序列化仍保持對象的唯一性。
private transient Object elementData;//Object數組,transient關鍵字不知道的同學自己查資料去,帶transient關鍵字的變數不會序列化。ArrayList容器,基本操作都是基於該數組進行操作的。
private int size;//數組的大小。
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//要分配的數組的最大大小。
2.3、構造函數
ArrayList有三個構造函數:
ArrayList:默認構造函數,提供初始容量為10的空列表。
ArrayList(int initialCapacity):構造一個具有指定初始容量的空列表。
ArrayList(Collection extends E> c):構造一個包含指定 collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的。
/**
* 構造具有指定初始容量的空列表。.
*
* @param 初始容量列表的初始容量
* @throws IllegalArgumentException 如果指定的初始容量為負會拋出非法異常。
*/
public ArrayList(int initialCapacity) {
super;
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* 構建一個初始容量為十的空列表.
*/
public ArrayList {
this(10);
}
/**
* 構造包含指定元素的列表。
* 集合,按集合返回的順序
* 迭代器
*
* @param c的集合,其元素將放在這個列表中。
* @throws NullPointerException 如果指定的集合為null為拋出這個空指針異常。
*/
public ArrayList(Collection extends E> c) {
elementData = c.toArray;//如果為空,這裡會拋異常
size = elementData.length;
// c.toArray might (incorrectly) not return Object (see 6260652)
if (elementData.getClass != Object.class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
2.4、add方法
ArrayList提供了add(E e)、add(int index, E element)、addAll(Collection extends E> c)、addAll(int index, Collection extends E> c)、set(int index, E element)這個五個方法來實現ArrayList增加。
我就拿一個來講了,懂的一個,其他應該都懂了。
public boolean add(E e) {
ensureCapacityInternal(size + 1); //增加操作次數
elementData[size++] = e;//把值放到最後一位
return true;
}
private void ensureCapacityInternal(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);//新的容量為舊的1.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 小於0,拋異常
throw new OutOfMemoryError;
return (minCapacity > MAX_ARRAY_SIZE) ?//大於MAX_ARRAY_SIZE就設置為MAX_VALUE,否則就MAX_ARRAY_SIZE
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
2.5、remove方法
ArrayList提供了remove(int index)、remove(Object o)、removeRange(int fromIndex, int toIndex)、removeAll四個方法進行元素的刪除。
remove(int index):移除此列表中指定位置上的元素。
public E remove(int index) {//根據下標刪除
rangeCheck(index);//檢查是否越界
modCount++;//操作增加
E oldValue = elementData(index);//獲得下標的值
int numMoved = size - index - 1;//要移動的數據
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);//數組往前移
elementData[--size] = null; // 讓GC工作
return oldValue;//返回舊值
}
private void rangeCheck(int index) {//檢查越界
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {//是不是感覺經常空間這個,哈哈
return "Index: "+index+", Size: "+size;
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
remove(Object o):如果存在移除此列表中首次出現的指定元素。
public boolean remove(Object o) {
if (o == null) {//如果為null
for (int index = 0; index < size; index++)
if (elementData[index] == null) {//==來比較
fastRemove(index);
return true;//存在並刪除返回true
}
} else {//如果不為null
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {//equals來比較
fastRemove(index);//存在並刪除返回true
return true;
}
}
return false;//不存在返回false
}
private void fastRemove(int index) {
modCount++;//操作數增加
int numMoved = size - index - 1;//移動次數
if (numMoved > 0)//移動
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
2.6、get方法
public E get(int index) {
rangeCheck(index);//檢查是否越界
return elementData(index);//取值
}
2.7、注意subList方法
public static void main(String[] args) {
List
list1.add(1);
list1.add(2);
// 通過構造函數新建一個包含list1的列表 list2
List
// 通過subList生成一個與list1一樣的列表 list3
List
// 修改list3
list3.add(3);
System.out.println(list1.size);
System.out.println("list1 == list2:" + list1.equals(list2));
System.out.println("list1 == list3:" + list1.equals(list3));
}
上面一段代碼我感覺大部人都會認為結果是2個false,list2是新構造的肯定與list1不一樣,list3是截取的肯定也不一樣。所以會認為都是false,我們深入subList去看看。
public List 原來sublist裡面操作的是原來的list,並沒有生成新的list,導致2個其實是一樣的。 所以上面正確的結果是: list1 == list2:false list1 == list3:true 因為它是基於數組實現的,主要有如下特點: 1、插入、刪除比較慢,因為插入、刪除需要移動數據位置。 2、可以重複插入數據、可以插入null。 3、查找比較快,可以直接使用下標。
subListRangeCheck(fromIndex, toIndex, size);//檢查下標和大小
return new SubList(this, 0, fromIndex, toIndex);//新創建一個SubList對象,注意傳入的是this,代表了要截取的對象
}
private class SubList extends AbstractList
private final AbstractList
private final int parentOffset;
private final int offset;
int size;//我擦,熟悉的感覺
SubList(AbstractList
this.parent = parent;//this.parent = parent;而parent就是在前面傳遞過來的list,也就是說this.parent就是原始list的引用。
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;//操作數也是跟原來的一樣
}
※easygen通用代碼生成框架
※vue-schart:vue.js 的圖表組件
※Java基礎——關於訪問許可權的一道例題
TAG:科技優家 |