AbstractCollection
此类提供了Collection
接口的基本实现,以最大程度地减少实现此接口所需的工作。
要实现一个不可修改的集合,编程者只需扩展此类并为iterator
和size
方法提供实现。 (iterator
方法返回的迭代器必须实现hasNext
和next
。)
要实现一个可修改的集合,编程者必须另外重写此类的add
方法(否则将抛出UnsupportedOperationException
),并且iterator
方法返回的迭代器必须另外实现其remove
方法。
按Collection
照接口规范中的建议,程序员通常应提供void
(无参数)的Collection
构造函数。
此类中每个非抽象方法的文档都详细描述了其实现。如果正在实现的集合有更有效的实现,则可以重写这些方法中的每一个。
该类是Java集合框架中的一员。
唯一的构造函数。 (用于子类构造函数的调用,通常是隐式的。)
源码如下:
protected AbstractCollection() {
}
抽象方法,返回此集合中所包含元素的迭代器。
抽象方法,返回此集合所包含的元素数量。
判断当前集合是否为空,底层是通过调用size()
获取当前集合的元素数量,然后判断元素数量是否为0。
源码如下:
public boolean isEmpty() {
return size() == 0;
}
此实现对集合中的元素进行迭代,依次检查每个元素是否与参数中给定的元素相等。
使用该集合的迭代器遍历当前集合,如果参数中给定的参数o
为null
,则判断当前集合中是否存在为null
的元素。如果参数中给定的参数不为null
,则通过equals
判断当前集合中是否存在和给定元素o
相等的元素。
源码如下:
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;
}
此实现返回一个数组,该数组包含所有通过该集合的迭代器返回的元素,元素以相同的顺序在数组连续存在,从索引0
开始。返回数组的长度等于迭代器返回的元素数(即使此集合的大小在迭代过程中发生了变化,如果该集合允许在迭代过程中进行并发修改,就可能会发生这种情况)。size
方法仅作为优化提示被调用,即使迭代器返回不同数量的元素,也将返回正确的结果。
该方法等同于:
List<E> list = new ArrayList<E>(size());
for (E e : this)
list.add(e);
return 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();
// 遍历当前集合,截止索引为当前集合的元素个数减1
for (int i = 0; i < r.length; i++) {
// 如果未遍历完却发现迭代器已迭代至末尾了,说明元素比期望的要少,此时也不报错,而是复制一个数组返回
if (! it.hasNext()) // fewer elements than expected
return Arrays.copyOf(r, i);
r[i] = it.next();
}
// 如果遍历完成,但迭代器仍未至末尾,此时调用finishToArray方法重新分配数组并完成剩余元素的填充
return it.hasNext() ? finishToArray(r, it) : r;
}
此实现返回一个数组,此数组包含所有通过该集合的迭代器返回的元素,元素以相同的顺序在数组中连续存在,从索引0
开始。如果迭代器返回的元素数量太多而无法容纳到指定的数组中,那么元素也会以新分配数组的形式返回,其长度等于迭代器返回的元素数量,即使此集合的大小发生变化(如果在迭代过程中集合允许并发修改,则可能会发生这种情况)。size
方法仅作为优化提示被调用,即使迭代器返回不同数量的元素,也将返回正确的结果。
该方法等同于:
List<E> list = new ArrayList<E>(size());
for (E e : this)
list.add(e);
return list.toArray();
源码如下:
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
// 声明一个数组r,若指定数组a的容量大于等于集合的元素个数,说明数组a可以容纳当前集合的所有元素,此时r取指定的数组a
// 否则,说明指定的数组a不足以容纳当前列表的所有元素,此时重新分配一个容量为当前集合元素个数的数组,并赋值给r
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++) {
// 未遍历结束,但迭代器已至末尾,说明集合的元素在toArray过程中变少了
if (! it.hasNext()) { // fewer elements than expected
if (a == r) {
// 如果数组r就是指定的数组a,则此处第i个元素置为null
r[i] = null; // null-terminate
} else if (a.length < i) {
// 进入此分支,说明在声明数组r的时候,r是新分配的数组,而非指定的a
// 如果数组a的长度小于此处i,则复制一个数组返回
return Arrays.copyOf(r, i);
} else {
// 进入此分支,说明在声明数组r的时候,r是新分配的数组,而非指定的a,且a的长度大于等于i,此时进行数组复制,把r复制给a
System.arraycopy(r, 0, a, 0, i);
if (a.length > i) {
// 如果a的长度大于i,则i位置的元素置为null
a[i] = null;
}
}
// 返回数组a
return a;
}
r[i] = (T)it.next();
}
// more elements than expected
// 如果遍历完成,发现仍未至迭代器的末尾,则调用finishToArray重新分配数组并完成剩余元素的填充
return it.hasNext() ? finishToArray(r, it) : r;
}
可分配的最大数组大小。一些虚拟机在数组中保留一些头字。尝试分配更大的数组可能会导致OutOfMemoryError
:请求的数组大小超出虚拟机限制。
当迭代器返回的元素比预期的多时,在toArray
中重新分配正在使用的数组,并完成从迭代器中填充它的操作。
源码如下:
@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);
}
// 在数组的i索引位置放置当前遍历到的元素,然后i加1
r[i++] = (T)it.next();
}
// trim if overallocated
// 如果重新分配后数组长度过长,则进行数组复制以实现trim效果
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");
// 如果最小容量需求大于集合所允许的最大数组容量,则此时取当前虚拟机所支持的Integer最大值
// 否则就取集合所允许的最大数组容量
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
该方法的默认实现为抛出UnsupportedOperationException
。
源码如下:
public boolean add(E e) {
throw new UnsupportedOperationException();
}
此实现遍历集合以查找指定的元素。如果找到该元素,则使用迭代器的remove
方法从集合中删除该元素。
请注意,如果此集合的iterator
方法返回的迭代器未实现remove
方法并且该集合包含指定的对象,则此实现将引发UnsupportedOperationException
。
源码如下:
public boolean remove(Object o) {
Iterator<E> it = iterator();
// 当指定元素为null时,遍历集合,对每个元素执行 “== null”的判断
// 否则,使用equals方法判断,找到对应对象后,使用迭代器的remove方法删除
// 从此实现上看,仅删除第一个命中的元素,删除后即返回true
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;
}
此实现将遍历给定的集合,依次检查每个元素以查看其是否包含在此集合中。如果所有元素都包含,则返回true
,否则返回false
。
源码如下:
public boolean containsAll(Collection<?> c) {
// 遍历指定集合c,然后调用contains方法判断每一个迭代到的元素是否存在于当前集合中
// 发现有一个不包含则直接返回false
for (Object e : c)
if (!contains(e))
return false;
return true;
}
此实现遍历给定的集合,并将迭代器返回的每个对象依次添加到此集合。
请注意,除非重写add
(假定指定的集合为非空),否则此实现将抛出UnsupportedOperationException
。
源码如下:
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
// 遍历指定的集合c
for (E e : c)
// 调用add方法添加元素到当前集合
if (add(e))
modified = true;
return modified;
}
此实现遍历当前集合,依次检查迭代器返回的每个元素以查看其是否包含在指定的集合中。如果包含,则使用迭代器的remove
方法将其从此集合中删除。
请注意,如果iterator
方法返回的迭代器未实现remove
方法并且此集合的确包含给定集合的一个或多个元素,则此实现将抛出UnsupportedOperationException
。
源码如下:
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<?> it = iterator();
// 遍历当前集合
while (it.hasNext()) {
// 使用指定集合的contains方法判断是否包含当前迭代到的元素
if (c.contains(it.next())) {
// 如果包含,使用迭代器的remove方法删除
it.remove();
modified = true;
}
}
return modified;
}
此实现遍历当前集合,依次检查迭代器返回的每个元素以查看其是否包含在指定的集合中。如果没有包含,则使用迭代器的remove
方法将其从此集合中删除。
请注意,如果iterator
方法返回的迭代器未实现remove
方法并且此集合的确包含给定集合中一个或多个不存在的元素,则此实现将抛出UnsupportedOperationException
。
总体来说,该方法执行后,当前集合中仅剩余当前集合和指定集合中均存在的元素。
源码如下:
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;
}
此实现遍历当前集合,并使用Iterator.remove
操作删除每个元素。大多数实现可能会选择重写此方法以提高效率。
请注意,如果此集合的iterator
方法返回的迭代器未实现remove
方法并且该集合非空,则此方法将抛出UnsupportedOperationException
。
源码如下:
public void clear() {
Iterator<E> it = iterator();
// 遍历当前集合,使用迭代器删除每个元素
while (it.hasNext()) {
it.next();
it.remove();
}
}
返回此集合的字符串表示形式。字符串表示形式包括一个集合元素的列表,这些元素按其迭代器返回的顺序排列,并括在方括号([]
)中。相邻元素由字符,
(逗号和空格)分隔。元素通过String
的valueOf(Object obj)
方法转换为字符串。
源码如下:
public String toString() {
Iterator<E> it = iterator();
// 如果当前集合为空,则返回[]
if (! it.hasNext())
return "[]";
// 使用StringBuilder进行拼接
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
// 如果当前元素就是当前集合,则此时使用“(this Collection)”来展示
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}