java集合類源碼學習二
我們查看Collection接口的hierarchy時候,可以看到AbstractCollection<E>這樣一個抽象類,它實現了Collection接口的部分方法,Collection集合系列的各個集合類都繼承于該抽象類。我們來看看這個類:
public abstract class AbstractCollection<E> implements Collection<E> {
protected AbstractCollection() {
}
public abstract Iterator<E> iterator();
public abstract int size();
public boolean isEmpty() {
return size() == 0;
}
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;
}
public Object[] toArray() {
// Estimate size of array; be prepared to see more or fewer elements
Object[] r = new Object[size()];
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) // fewer elements than expected
return Arrays.copyOf(r, i);
r[i] = it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
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()) { // fewer elements than expected
if (a == r) {
r[i] = null; // null-terminate
} 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();
}
// more elements than expected
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;
// overflow-conscious code
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next();
}
// trim if overallocated
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;
}
public boolean add(E e) {
throw new UnsupportedOperationException();
}
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;
}
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
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;
}
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;
}
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(' ');
}
}
}
從它的代碼里我們可以看到,它有一個最大長度,是Integer的最大值減去8,至于為什么減8,是因為有些JVM會在數組里保存幾個關鍵字符。我們再看這個contains方法,我很好奇的是,既然參數是Object類型,那么就包括了null,為什么判斷的時候還要把null單獨拿出來,這個疑問不知哪個大佬能給我解釋一下。
再看toArray的不帶參方法,new了一個和size()方法表示的長度一樣長的Object數組r,還弄了一個迭代器出來,然后用for來循環r數組的每一個下標,并在每一次循環中判斷迭代器的hasNext()是否為false,如果為false則說明當前集合長度比r數組短,則用Array的copyOf()方法把r數組放到一個長度為i的數組里,這樣就不浪費多余的空間了。最后判斷如果hasNext()還為true,則說明當前集合長度比r數組長,就用finishToArray()方法返回一個Object數組。至于為什么比較過和size()的大小之后還有這種操作,上面注釋有說明,是迭代的時候假如對元素有增刪操作,會導致長度有變化。finishToArray(T[] r, Iterator<?> it)方法把數組r擴容之后往里面添加迭代器后續元素,可以看到hugeCapacity這個玩意,當數組長度超過Integer最大值減8的時候,就用Integer的最大值,這樣數組的長度是不能超過2^31的,畢竟數組下標使用int數字表示的。帶參的toArray方法差不多意思,是可以將集合轉化成指定類型的數組。
add()方法會直接拋出異常,說明AbstractCollection是不允許添加元素的,那么一定是在具體實現類里實現的這個方法。至于其他的方法,看一下就明白了。
接著我們來看看public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>,這是list的抽象類,繼承自AbstractCollection,實現List接口的部分方法。源碼就不貼了,現在重點來看一下內部類Itr,這是一個迭代器的實現類。里面定義了三個變量:游標cursor、最近一次調用返回的索引lastRet和期望得到的修改次數expectedModCount。里面實現了迭代器的三個方法,注意next()和remove()方法里都調用了這么一個方法checkForComodification(),這個用來比較expectedModCount和modCount,如果不同就拋出異常ConcurrentModificationException,這個意思是如果在迭代操作的時候,如果有用非迭代器的操作對集合做了修改,那么就會拋出異常。對于modCount,我們可以在AbstractList的子類中看到,每次對集合做了操作,modCount就會加一。
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(11);
list.add(12);
list.add(13);
list.add(14);
list.add(15);
Iterator<Integer> itr = list.iterator();
while(itr.hasNext()) {
if(itr.next() == 13) {
itr.remove();
}
}
System.out.println(list);
}
在迭代的時候用迭代器的remove操作就不會報錯,如果在增強for循環中,用了ArrayList自帶的remove,就會報異常了。下面的內部類ListItr是一個ListIterator的實現類,可以往前往后迭代,還有多了幾個方法,代碼都很簡單。subList()截取一段子序列,支持往前往后截取。下面還有個SubList類,里面有個往后截取一段子序列的方法,其他的起始都是用的父類的方法。

浙公網安備 33010602011771號