Collection容器家族(AbstractCollection超类)
一、AbstractCollection超类位置及概述
四个超类AbstractCollection、 AbstractSet 、AbstractList、AbstractSequentialList。AbstractCollection、 AbstractSet 、AbbstractList根据名字就可以知道,他们分别对Collection,Set、List接口进行了实现,但对三个接口的是实现是部分实现,因为关于存储的数据结构是父类超类无法知道的,它只能实现公共已知的方法。AbstractSequentialList继承了AbstractList这个类提供
了一个基本的List接口实现,为实现序列访问的数据储存结构的提供了所需要的最小化的接口实现。
AbstractCollection超类继承自Collection接口,实现部分方法,同时为AbstractSet 、AbstractList、AbstractSequentialList三个超类的父类。
二、AbstractCollection源码讲解
AbstractCollection是Collection的实现类,它实现了Collection的部分方法,也留下了一些方法让子类去实现。
没有实现的方法及描述:
// Query Operations
/**
* Returns an iterator over the elements contained in this collection.
*
* @return an iterator over the elements contained in this collection
*/
public abstract Iterator<E> iterator(); // 迭代器方法
public abstract int size(); // 集合的大小(集合中元素的个数)
实现了没写内容且不能使用的方法:
/**
* {@inheritDoc}
*
* <p>This implementation always throws an
* <tt>UnsupportedOperationException</tt>.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalStateException {@inheritDoc}
*/
public boolean add(E e) {
throw new UnsupportedOperationException();
}
在AbstractCollection超类中凡是需要调用iterator(), size(), add()的方法均不能使用。
实现的方法及描述:
1.判空方法 isEmpty()
/**
* {@inheritDoc}
*
* <p>This implementation returns <tt>size() == 0</tt>.
*/
public boolean isEmpty() { // 判断集合是否为空
return size() == 0; // 通过判断集合的元素个数判断
}
2.集合查找元素 contains(Object o)
/**
* 判断是否包含指定的元素
* (1)如果参数为null,查找值为null的元素,如果存在,返回true,否则返回false。
* (2)如果参数不为null,则根据equals方法查找与参数相等的元素,如果存在,则返回true,否则返回false。
* 注意:这里必须对null单独处理,否则null.equals会报空指针异常
*/
public boolean contains(Object o) { // 在集合中查找指定元素方法
Iterator<E> it = iterator(); // 获取本集合迭代器
if (o==null) { // 待查找元素为null
while (it.hasNext()) // 遍历集合,如果有null则打破循环,直接返回true
if (it.next()==null)
return true;
} else { // 待查找元素不为null
while (it.hasNext()) // 遍历集合,通过equals方法比较是否相等,相等则直接返回true
if (o.equals(it.next()))
return true;
}
return false; // 没有找到返回false
}
3.集合转Object类型数组 toArray() (注意:出现集合元素个数比预期大或小是因为并发修改)
/**
* 功能:将集合元素转换为Object类型数组
* 实现:(出现集合的元素个数比预期大或小,是因为该方法允许并发修改)
* (1)创建一个数组,大小为集合中元素的数量
* (2)通过迭代器遍历集合,将当前集合中的元素复制到数组中
* (3)如果集合中元素比预期的少,则调用Arrays.copyOf()方法将数组的元素复制到新数组中,并返回新数组
* (4)如果集合中元素比预期的多,则调用finishToArray方法生成新数组,并返回新数组,否则返回(1)中创建的数组
*/
public Object[] toArray() {
// Estimate size of array; be prepared to see more or fewer elements
Object[] r = new Object[size()]; // 创建集合大小的Object类型数组
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; // 如果集合元素比预期多,则调用finishToArray方法生成新数组,并返回新数组,否则返回(1)中创建的数组
}
4.集合转指定类型数组 toArray(T[] a)
/**
* 功能:通过泛型约束返回指定类型的数组
* 实现:
* (1)如果传入数组的长度的长度大于等于集合的长度,则将当前集合的元素复制到传入的数组中
* (2)如果传入数组的长度小于集合的大小,则将创建一个新的数组来进行集合元素的存储
*/
@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 : // 将参数a的大小与集合大小比较,参数a大则使用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) { // 如果数组是参数中的数组,则将剩余部分的值都设置为null
r[i] = null; // null-terminate
} else if (a.length < i) { // 如果传入的数组长度小于集合长度,则通过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[i] = (T)it.next(); // 对数组进行赋值
}
// more elements than expected
return it.hasNext() ? finishToArray(r, it) : r; // 集合元素大小大于数组的长度
}
/**
* 功能:数组扩容
* (1)当数组索引指向最后一个元素+1时,对数组进行扩容:即创建一个更长的数组,然后将原数组的内容复制到新数组中
* (2)扩容大小:cap + cap/2 +1
* (3)扩容前需要先判断是否数组长度是否溢出
* 注意:这里的迭代器是从上层的方法(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);
}
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;
}
5.删除集合指定元素 remove(Object o)
/**
* 功能:移除指定元素
* 实现:
* (1)如果参数为null,则找到第一个值为null的元素,并将其删除,返回true,如果不存在null的元素,返回false。
* (2)如果参数不为null,则根据equals方法找到第一个与参数相等的元素,并将其删除,返回true,如果找不到,返回false。
*/
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;
}
6.是否包含指定集合 containsAll(Collection<?> c)
/**
* 功能:是否包含指定集合
* 实现:
* (1)增强for遍历参数集合,根据contains找到一个不包含的元素则返回false,如果都存在返回true
*/
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
7.添加一个集合的元素 addAll(Collection<? extends E> c)
/**
* 功能:添加一个集合的元素
* 实现:
* (1)遍历集合,依次将元素添加到集合中
*/
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
8.移除参数集合的元素 removeAll(Collection<?> c)
/**
* 功能:移除参数集合的元素
* 实现:
* (1)判断参数集合是否为空,为空则抛出异常;获取迭代器
* (2)遍历集合,如果当前元素在集合中,则移除
* 注:只要参数集合有一个在当前集合中,就会返回true;返回值代表当前集合的变化
*/
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;
}
9.求参数集合与当前集合的交集 retainAll(Collection<?> c)
/**
* 功能:求参数集合与当前集合的交集
* 实现:
* (1)获取当前集合的迭代器进行遍历
* (2)如果当前集合的元素不在参数集合中,则移除
* 注意:如果当前集合是参数集合中的子集,则返回false,表示当前集合未发送变化,否则返回true。
*/
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;
}
10.删除集合的所有元素 clear()
/**
* 功能:删除集合的所有元素
* 实现:
* (1)对当前集合迭代遍历,逐一删除
*/
public void clear() {
Iterator<E> it = iterator();
while (it.hasNext()) {
it.next();
it.remove();
}
}
11.toString方法,很关键,我们的所用的集合能输出出集合中的内容,这个实现起到了关键性的作用
/**
* 功能:将集合转成字符串
* 实现:
* (1)//把集合中的所有数据转变成了字符串,采用的是线程不安全的效率高的StringBuilder()类来拼接。
*/
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(' ');
}
}
三、总结
AbstractCollection超类作为collection顶层接口的第一个实现类,它实现了所有类功能相似(操作与存储结构无关的操作);一方面为其之类减轻重写负担(专业用语:提取出之类共性的方法去实现)。
为什么没有实现iterator()、size()、add()三个方法?
1.因为add实现的方式有很多不能确定子类是哪种数据结构(链表,数组,Map(数组+链表)),所以我们没法去显示的实现 它,就算间接的用某种方式实现,也显得太过冗余而没有必要。
2.为什么没规定为抽象方法,是因为如果子类不想用add子类就是一个删改查的集合。那么我们不用还必须要去实现岂不是 很矛盾。