第一篇技术博客,有错误的地方希望网友指出。
这边博客的主要内容是分析java的Collection接口、它的一个抽象类AbstractCollection.
一、Collection接口
package java.util;
public interface Collection<E> extends Iterable<E> {
int size(); //返回大小
boolean isEmpty(); //是否为空
boolean contains(Object o); //集合中是否包含某对象
Iterator<E> iterator(); //迭代器(用于遍历)
Object[] toArray(); //装换为数组 java中的集合都是由数组实现的
<T> T[] toArray(T[] a); //转换为数组
boolean add(E e); //添加
boolean remove(Object o); //删除
boolean containsAll(Collection<?> c); //包含全部
boolean addAll(Collection<? extends E> c); //添加集合
boolean removeAll(Collection<?> c); //移除全部
boolean retainAll(Collection<?> c); //保留所有(移除其他的)
void clear(); //清除全部
boolean equals(Object o); //相等
int hashCode(); //哈希值
}
Collection 接口是所有集合的root interface,接口中共有以上的方法,对于以上方法,不同的子接口会有不同的实现。
Collection 接口主要包含一些基本的遍历和增删改查等。
二、AbstractCollection抽象类
AbstractCollection对Collection对象的部分方法进行了实现。
2.1 属性
/**
* 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;
这里定义了集合的最大值,为整形的最大值减8,api的文档里说由于有的vm对于数组需要头文件,所有这个可能是在Integer最大值的基础上那减去8的原因。
2.2 方法
2.2.1 contains
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;
}
contains方法,集合是否包含某个对象,包含返回true,否则返回false。 方法开始会判断o是否为null,因为如果o为null,则调用.equals方法时会抛nullpointer异常。如果不为null,利用迭代器遍历集合,调用o的equals方法去比较,看是否存在于集合中(注:Object的equals方法用的==比较).
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
2.2.2 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++) {
if (! it.hasNext()) // fewer elements than expected
return Arrays.copyOf(r, i);
r[i] = it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
toArray方法是将集合装换为对象的数组,通过size()方法拿到当前集合中对象的个数,然后通过迭代器遍历集合,将集合填入数组中。
这本来是个很简单的过程,但是由于Collection接口本身是未同步的,所以size方法得到的个数和迭代器中的个数未必相等。当迭代器中的个数少于定义的数组时,值返回数组的一部分。
当迭代器中的个数多余数组时,则调用了finishToArray方法:
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);
}
该方法中先对数组进行扩容,同时会检查数组大小是否超过最大值,如果超过了就调用hugeCapacity方法对数组的大小进行控制,最后把原数组拷贝到新扩容的数组中。当然,当i值又到达了容器的容量,又会重新扩容。最后,会看下数组的大小是否超过迭代器,如果超过就做trim处理。
对于toArray(T[] a)方法是对toArray()方法基础上加上了泛型限制:
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); //if a's size is smaller than elements size, create a larger array
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;
}
该方法首先检查a数组是否比集合中个数多,如果多则将a赋给r;如果少,则利用反射重新建一个size大小的数组赋给r。进行r的大小次迭代,迭代器中有值,则赋予数组r;如果迭代器中没有值了,这说明,在迭代期间,已经进行了删除操作,数组元素减少了。
此时,如果r就是a,则数组r中其余的值用null填充;如果a的值比i小,说明r是新建的,我们只需要返回r的一部分就可以了;第三种情况,a的length大于等于当前的i,把r中的数组copy回a中,如果a的length大于i,其余的用null填充。
最后的情况是迭代器中个数多余r,则依然调用finishToArray()。
2.2.3 remove
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;
}
迭代,如果o为null,找到第一个为null的移除;如果不为null,找到第一个equals的对象,移除。由于null调用equals会报异常,所以null要做特殊处理。
2.2.4 其他
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) {
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) {
boolean modified = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}