Java基礎系列(四十):集合之AbstractCollection
前言
(PS:上週由於準備自考,更新延誤了一些,見諒!)
AbstractCollection
類是Collection
介面的一個實現類,它只是為了給我們提供了一些最基礎的介面的實現,在實際的應用中,我們並不會去使用這個類來封裝一些資訊,接下來我們首先去看一下這個類的繼承關係圖。
結構圖
由此可以看出AbStractCollection
只是實現了Collection
介面,並沒有實現或者繼承其他的類或者介面。接下來,我們來看一下這個類的原始碼,看看會有什麼收穫。
原始碼
package java.util;
//TAG 1
public abstract class AbstractCollection<E> implements Collection<E> {
protected AbstractCollection() {
}
public abstract Iterator<E> iterator();
public abstract int size();
//TAG 2
public boolean isEmpty() {
return size() == 0;
}
//TAG 3
public boolean contains(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return true;
} else {
while (it.hasNext())
if (o.equals(it.next()))
return true;
}
return false;
}
//TAG 3
public Object[] toArray() {
Object[] r = new Object[size()];
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext())
return Arrays.copyOf(r, i);
r[i] = it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
//TAG 3
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
T[] r = a.length >= size ? a :
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) {
if (a == r) {
r[i] = null;
} else if (a.length < i) {
return Arrays.copyOf(r, i);
} else {
System.arraycopy(r, 0, a, 0, i);
if (a.length > i) {
a[i] = null;
}
}
return a;
}
r[i] = (T)it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
//TAG 4
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//TAG 5
@SuppressWarnings("unchecked")
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) {
int newCap = cap + (cap >> 1) + 1;
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next();
}
return (i == r.length) ? r : Arrays.copyOf(r, i);
}
//TAG 6
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError
("Required array size too large");
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
//TAG 7
public boolean add(E e) {
throw new UnsupportedOperationException();
}
//TAG 3
public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext()) {
if (it.next()==null) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}
//TAG 3
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
//TAG 3
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
//TAG 3
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
//TAG 3
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
//TAG 3
public void clear() {
Iterator<E> it = iterator();
while (it.hasNext()) {
it.next();
it.remove();
}
}
//TAG 3
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
}
TAG 1 :
從關鍵字abstract
可以看出這個類是一個抽象類,這個類只是實現了一部分的介面,還遺留了一部分介面需要我們在子類中去實現。
TAG 2 :
isEmpty()
方法通過size()
介面是否等於0來判斷,而size()
介面的實現交給了更為具體的集合類去實現。
TAG 3 :
contains()
,remove()
,containsAll()
,addAll()
,removeAll()
,retainAll()
,clear()
,toString()
這些方法我們通過閱讀原始碼可以知道,都是通過迭代器來實現的,其中有一些方法使用了增強for迴圈,但其實編譯器會將增強for迴圈編譯為使用迭代器的遍歷操作。
TAG 4 :
陣列作為一個物件,需要一定的記憶體儲存物件頭資訊,物件頭資訊最大佔用記憶體不可超過8 byte。
TAG 5 :
finishToArray(T[] r, Iterator<?> it)
方法用於陣列擴容,當陣列索引指向最後一個元素+1時,對陣列進行擴容:即建立一個大小為(cap + cap/2 +1)的陣列,然後將原陣列的內容複製到新陣列中。擴容前需要先判斷是否陣列長度是否溢位。這裡的迭代器是從上層的方法(toArray(T[] t)
)傳過來的,並且這個迭代器已執行了一部分,而不是從頭開始迭代的
TAG 6 :
hugeCapacity(int minCapacity)
方法用來判斷該容器是否已經超過了該集合類預設的最大值即(Integer.MAX_VALUE -8
),一般我們用到這個方法的時候比較少,後面我們會在ArrayList
類的學習中,看到ArrayList
動態擴容用到了這個方法。
TAG 7 :
這裡的add(E)
方法預設丟擲了一個異常,為什麼這樣去定義呢?而不是直接定義為抽象方法?
如果我們想修改一個不可變的集合時,丟擲 UnsupportedOperationException
是正常的行為,比如當你用 Collections.unmodifiableXXX()
方法對某個集合進行處理後,再呼叫這個集合的修改方法(add
,remove
,set…
),都會報這個錯。因此 AbstractCollection.add(E)
丟擲這個錯誤是準從標準。
而之所以沒有定義為抽象方法,是因為可能有很多地方用不到這個方法,用不到還必須實現,這豈不是讓人很困惑麼。(PS:參考自拭心)
toArray詳解
在這個類中,我們需要詳細瞭解的方法是toArray
,正如其名,它可以把一個集合轉換為陣列,可以看到toArray
方法分為了兩種引數的方法:
/**
* 分配了一個等大空間的陣列,然後依次對陣列元素進行賦值
*/
public Object[] toArray() {
//新建等大的陣列
Object[] r = new Object[size()];
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
//判斷是否遍歷結束,以防多執行緒操作的時候集合變得更小
if (! it.hasNext())
return Arrays.copyOf(r, i);
r[i] = it.next();
}
//判斷是否遍歷未結束,以防多執行緒操作的時候集合變得更大,進行擴容
return it.hasNext() ? finishToArray(r, it) : r;
}
/**
* 泛型方法的`toArray(T[] a)`方法在處理裡,會先判斷引數陣列的大小,
* 如果空間足夠就使用引數作為元素儲存,如果不夠則新分配一個。
* 在迴圈中的判斷也是一樣,如果引數a能夠儲存則返回a,如果不能再新分配。
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
//當陣列a的長度大於等於a,直接將a賦予給r,否則使用反射API獲取一個長度為size的陣列
T[] r = a.length >= size ? a :
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
//判斷是否遍歷結束
if (! it.hasNext()) {
//如果 a == r,將r的每項值賦空,並將a返回
if (a == r) {
r[i] = null;
} else if (a.length < i) {
//如果a的長度小於r,直接呼叫Arrays.copyOf進行復制獲取一個新的陣列
return Arrays.copyOf(r, i);
} else {
System.arraycopy(r, 0, a, 0, i);
if (a.length > i) {
a[i] = null;
}
}
return a;
}
//如果遍歷結束,將迭代器獲取的值賦給r
r[i] = (T)it.next();
}
//判斷是否遍歷未結束,以防多執行緒操作的時候集合變得更大,進行擴容
return it.hasNext() ? finishToArray(r, it) : r;
}
/**
* 設定該容器的最大值
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 用於動態擴容
*/
@SuppressWarnings("unchecked")
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) {
int newCap = cap + (cap >> 1) + 1;
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next();
}
return (i == r.length) ? r : Arrays.copyOf(r, i);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError
("Required array size too large");
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
為了幫助瞭解,我把Arrays.copyOf(r.i)
的原始碼也貼出來:
//引數original代表你傳入的需要複製的泛型陣列,newLength複製得到陣列的大小
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
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