ArrayList簡介
-
概念
ArrayList是一個容量能夠動態增長的動態數組。和java的數組相比,它的容量能夠動態增長。它繼承了AbstractList,實現了List、RandomAccess、Cloneable、java.io.Serializable
-
繼承關係
首先,我們先查看下ArrayList在java集合體中所在的位置:
在這裏我們可以看到ArrayList的根部是Collection,下面我們看分析下ArrayList的繼承關係
上圖清晰的描述到,實現四個接口繼承一個抽象類:
- ArrayList繼承AbstractList;實現List。它是一個數組隊列,提供了新增、修改、刪除和遍歷等功能。
- ArrayList實現了RandomAccess,即提供了隨機訪問功能。
- ArrayList實現了Cloneable,即覆蓋了函數clone(),能夠被克隆。
- ArrayList實現了java.io.Serializable,這表明ArrayList可以被序列化,能通過序列化去傳輸。
- 和Vector不同,ArrayList操作的是線程不安全的,建議在單線程的情況下使用,如果是多線程的情況下建議使用Vector和CopyOnWriteArrayList
-
從ArrayList源碼分析
1.ArrayList屬性:
ArrayList屬性主要有當前數組長度size、存放數組對象elementData數組和代表ArrayList修改次數從AbstractList繼承的modCount屬性。
// 序列化id
private static final long serialVersionUID = 8683452581122892189L;
// 默認初始化容量大小
private static final int DEFAULT_CAPACITY = 10;
// 用於空實例時共享空數組實例
private static final Object[] EMPTY_ELEMENTDATA = {};
// 一個空對象,如果使用默認構造函數創建,則默認對象內容默認是該值
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 當前數據對象存放地方
transient Object[] elementData; // non-private to simplify nested class access
// 當前數組的長度
private int size;
2.ArrayList的構造方法:
ArrayList構造方法有三種,分別是默認不傳參、初始化容量的空數組和包含元素的數組。
- 無參構造函數,初始容量爲10的空數組,如下:
// 第一種,調用ArrayList(10),其中初始化的一個長度爲10的object數組
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 初始化大小的構造函數,如下:
public ArrayList(int initialCapacity) {
// 如果初始化大小小於0會報異常,否則新建初始化爲object的數組
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
- 帶collection對象的構造方法,
1)先將集合轉換成數組,然後賦值給elementData;
2)將數組長度賦值給size並判斷是否爲0,
如下:
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
1.0、這邊談一下ArrayList(Collection<? extends E> c)是深拷貝還是淺拷貝,測試代碼如下:
/** 測試ArrayList(Collection<? extends E> c)是淺拷貝還是深拷貝 **/
List<BeanDemo> beanDemos = new ArrayList<>();
BeanDemo beanDemo = new BeanDemo();
beanDemo.setName("test1");
beanDemos.add(beanDemo);
List<BeanDemo> beanDemoList = new ArrayList<>(beanDemos);
beanDemo.setName("test2");
System.out.println(beanDemoList.get(0).getName());
//結果輸出test2
1.2、深入研究一下源碼,爲什麼ArrayList(Collection<? extends E> c)構造函數是淺拷貝,其中調用了Arrays.copyof()方法,傳參是原始數組和拷貝數組的長度,copyof()通過獲取一個原始數組的副本,被截斷或用null填充以返回指定的長度。源碼如下,到這一步還看不出是到底是淺拷貝還是深拷貝:
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
1.3、copyof()方法中主要使用System.arraycopy()方法來實現列表拷貝,再往下查看System.arraycopy(),發現這個是一個原生native的函數(native方法不是用java實現的),我只能仔細閱讀一下這個原生方法的註釋,參見文章最下方,註釋內容比較長,但第一段註釋直接告訴了我們arraycopy()方法拷貝的是數組的引用地址,所以它屬於淺拷貝:A subsequence of array components are copied from the source array referenced by src
to the destination array referenced by dest
.
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
2.0、爲何要判斷elementData.getClass() != Object[].class,當我們查看c.toArray()源碼的時候肯定認爲返回的就是Object[]數組,爲什麼還需要判斷呢?在查閱了各種資料之後才知道Arrays含有一個asList方法,Arrays.asList
體現的是適配器模式,只是轉換接口,後臺的數據仍是數組。
用代碼來證實下:
List<String> llll = Arrays.asList("zhen", "xiang");
System.out.println(llll.toArray().getClass());
//返回結果:class [Ljava.lang.String;
到這ArrayList集合的三種構造方法就講完了。下一篇會繼續講解它的其他方法~~~
借鑑資料:
1.源碼分析:
https://blog.csdn.net/augfun/article/details/82323164
https://baijiahao.baidu.com/sid=1637926321175819771&wfr=spider&for=pc
2.判斷toArray()方法是否返回Object[]:
https://blog.csdn.net/weixin_43390562/article/details/101236699
3.判斷ArrayList(Collection<? extends E> c)是深拷貝還是淺拷貝:
https://blog.csdn.net/king0406/article/details/103752855