AbstractCollection和AbstractList源码简单分析
一、AbstractCollection
AbstractCollection是一个抽象类实现了Collection接口。源码如下,主要显示一些新增的方法和重写后有区别的方法。
package java.util;
public abstract class AbstractCollection<E> implements Collection<E> {
protected AbstractCollection() {
}
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 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 void clear() {
Iterator<E> it = iterator();
while (it.hasNext()) {
it.next();
it.remove();
}
}
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(' ');
}
}
}
可以看出,实现这个类需要重写size()方法和iterator()方法。调用add()会抛出抛出异常,并且在具体的方法中,则需要覆盖这个方法,并且调用类中的方法获取Iterator后,也需要实现hasNext()、next()和remove()方法(回头看javaAPI中的总结更规范)。这个类是一个中间类,该类提供了Collection接口的骨架实现,以尽量减少实现此接口所需的工作量,相比较,List接口定义了更多的集合方法,这就是抽象与实现的分离吗。
下面看几个比较稍复杂的方法:
toArray()
返回一个包含此集合中所有元素的数组。
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++) {
//(1)
if (! it.hasNext()) // fewer elements than expected
return Arrays.copyOf(r, i);//(2)
r[i] = it.next();
}
//(3)
return it.hasNext() ? finishToArray(r, it) : r;
}
这个方法中应用了大量的判断来保证集合转数组赋值的准确性(多线程执行),这就指的是线程安全的方法吗?
逻辑分析下:
1.如果数组的大小等于迭代器遍历的次数相同,直接返回 步骤(3)的经过遍历赋值的数组r
2.如果数组的大小小于迭代器遍历的次数,走步骤(3)中的 finishToArray()
2.如果数组的大小大于迭代器遍历的次数,走步骤(2)中的 Arrays.copyOf()方法,对数组进行截断补充
看步骤(2)的Arrays.copyOf()方法:
public class Arrays {
...
@SuppressWarnings("unchecked")
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")
//(4)
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
//(5)
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
步骤(4)中如果该对象的类型是数组,则创建个newLength大小的数组,否则通过Array.newInstance中的newArray()方法创建个新的对象再转成数组(猜测是用反射创建对象呢)。最后通过System.arraycopy()将源数组赋值到目标数组中。
步骤(5)将原始数组赋值到新数组中,返回结果。
看步骤(3):
@SuppressWarnings("unchecked")
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) {//(6)
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;
}
该方法补充剩余的元素到数组中。
步骤(6)中为自定义的扩展当前数组的大小,以避免添加数据时引起数组越界异常。
其中:
//就是 1.5cap + 1
int newCap = cap + (cap >> 1) + 1;
这个确定数组大小值的方式应该也是效率最高的方式了。
注:虚拟机在数组中保留了一些头字,所以数组的最大值比int常量最大值减去8。
toArray(T[] a)
返回包含此集合中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型。当参数数组大小大于原集合大小时,剩下的元素用null补充。
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
//(1)
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++) {
//(2)
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;
}
toArray()返回的是Object[]数组,而该方法返回的是参数类型的数组。
步骤(1):返回的数组大小取原集合大小与参数数组大小中的最大值。
大部分的逻辑和toArray()方法中的逻辑是一样的,在步骤(2)中更加详细的判断了可能出现的各种情况(我已经懵了)表明该方法是线程安全的,余下的元素用null补充。
举个ArrayList的例子:
ArrayList<String> testOne = new ArrayList<>();
testOne.add("1");
testOne.add("2");
testOne.add("3");
String[] testStringsOne = {"1","1"};
String[] testStringsTwo = {"6","6","6","6"};
String[] resArrayOne = testOne.toArray(testStringsOne);
String[] resArrayTwo = testOne.toArray(testStringsTwo);
resArrayOne中是[1,2,3]。resArrayTwo中是[1,2,3,null]。
其他
remove()方法可以移除空元素,toString()方法表明集合直接输出不是地址值,而是输出每个元素。
二、AbstractList
此类提供的骨干实现的List接口以最小化来实现该接口由一个“随机访问”数据存储备份所需的工作。
其中get和size方法为抽象方法,实例化对象需要重写方法,而调用add和set方法则会抛出异常,该类拓展了很多根据索引截取对象,和自定义迭代器更好的遍历列表实现功能。
AbstractList类中存在大量的内部类来实现具体的功能。
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
...
abstract public E get(int index);
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public int size() {
checkForComodification();
return size;
}
public int indexOf(Object o) {
ListIterator<E> it = listIterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return it.previousIndex();
} else {
while (it.hasNext())
if (o.equals(it.next()))
return it.previousIndex();
}
return -1;
}
public int lastIndexOf(Object o) {
ListIterator<E> it = listIterator(size());
if (o==null) {
while (it.hasPrevious())
if (it.previous()==null)
return it.nextIndex();
} else {
while (it.hasPrevious())
if (o.equals(it.previous()))
return it.nextIndex();
}
return -1;
}
protected transient int modCount = 0;
private class Itr implements Iterator<E> {
//由后续调用Next返回的元素的索引,光标
int cursor = 0;
//最近调用next或previous返回的元素的索引。如果通过调用remove删除此元素,则重置为-1。
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
//(1)
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
//(2)
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
}
ListItr和Itr是AbsractList的内部类,分别实现了Iterator和ListIterator的迭代功能,来对AbsractList列表实现更多的功能。
add方法
public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
boolean modified = false;
for (E e : c) {
add(index++, e);
modified = true;
}
return modified;
}
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size())
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size();
}
在列表中增加元素,实现添加元素的列表需要重写add()方法。
clear()
public void clear() {
removeRange(0, size());
}
protected void removeRange(int fromIndex, int toIndex) {
ListIterator<E> it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i<n; i++) {
it.next();
it.remove();
}
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
清空集合中的所有元素。
通过调用方法(1)Itr.next()和方法(2)Itr.remove()删除集合中的每一个元素,通过 cursor光标变量和lastRet标识位控制元素的删除,本质上还是在方法控制好cursor和lastRet的变量值,通过调用 get()方法和remove()方法逐个删除元素。
equals(Object o)
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
判断2个集合是否相等。
1.引用相同,集合的值相同,返回true。
2.不是List的一个实例,返回false。
3.遍历判断元素的值是否都相等,有一个元素不相等返回false,集合的大小是否都相等。
(其中:o1.equals(o2)方法,如果引用相同则返回true;该类型重写了equals方法例如String,Integer或其他自定义的类,值相同则返回true;其他大多数情况返回false)
indexOf(Object o)与lastIndexOf(Object o)
一个是从前往后遍历,一个是从后往前遍历(用hasPrevious()和previous()向前遍历),当出现该值时,返回索引值(索引值同样由ListItr中的变量cursor确定)否则返回-1
subList(int fromIndex, int toIndex)
返回此列表中指定的 fromIndex (含)和 toIndex之间的视图。
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
其中SubList和RandomAccessSubList都是AbstractList的实现类,专门来实现截取后的列表的各种操作数据的功能。
部分代码如下:
class SubList<E> extends AbstractList<E> {
private final AbstractList<E> l;
private final int offset;
private int size;
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
//**************************
l = list;
//**************************
offset = fromIndex;
size = toIndex - fromIndex;
this.modCount = l.modCount;
}
public E set(int index, E element) {
rangeCheck(index);
checkForComodification();
return l.set(index+offset, element);
}
public E get(int index) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
}
...
}
SubList类相当于列表截取后的包装对象,逻辑与AbtractList相同,只是在此基础上计算偏移量之后的值(fromIndex相当于偏移量,toIndex-fromIndex为新列表的大小)。
注:由于上图中代码中的
l = list;
所以修改subList()后的列表也会对原列表进行修改。