import java.util.Arrays;
import jdk.internal.util.ArraysSupport;
/**
* @Classname AbstractCollection:实现了一些方法,也定义了几个抽象方法留给子类实现,因此是个抽象类
* @note:Collection接口的定义和继承的Iterable都可以在这个抽象类中实现,可以减少实现类需要实现的方法
* @note:如果要实现一个不可修改的集合,只需要重写iterator和size接口
* @note:如果要实现可以修改的集合,还必须重写add方法(默认会抛出异常),返回的Iterator还需要实现remove方法
* @date 2021年7月6日 下午3:32:49
* @Version 1.0
*/
public abstract class AbstractCollection<E> implements Collection<E> {
// 默认的构造函数是protected,因此会推荐子类去创建一个无参的构造函数
protected AbstractCollection() {}
/**
* 仅有的两个抽象方法
*@Description:子类实现迭代器和子类大小,子类必须以自己的方式实现这两个方法
*/
public abstract Iterator<E> iterator();
public abstract int size();
// 实现判断集合元素是否为空
public boolean isEmpty() {
// 调用子类实现的size()方法
return size() == 0;
}
// 实现判断集合是否包含该元素,因为iterator的存在,进行一致性封装,对象的比较是通过equals()
public boolean contains(Object o) {
// 获取子类实现的迭代器,挨个遍历和比较
Iterator<E> it = iterator();
if(o==null) {
while(it.hasNext()) {
// 说明AbstractCollection实现类支持null元素
if(it.next()==null) {
return true;
}
}
}else {
while(it.hasNext()) {
// 传入的这个元素类需要重写equals()方法
if(o.equals(it.next())) {
return true;
}
}
}
return false;
}
// 实现判断集合中是否包含该集合的所有元素
public boolean containsAll(Collection<?> c) {
Iterator<?> it = c.iterator();
// 挨个遍历指定集合,这里的时间复杂度是次方阶
while(it.hasNext()) {
if(!c.contains(it.next())) {
return false;
}
}
return true;
}
// 实现删除集合中一个元素
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;
}
}
}
}
// 实现两个集合中保留共有的元素
public boolean retainAll(Collection<?> c) {
boolean result = false;
Iterator<?> it = c.iterator();
// 挨个遍历指定集合,这里的时间复杂度是次方阶
while(it.hasNext()) {
// 调用的是Collection接口的contains()?
if(!c.contains(it.next())) {
it.remove();
result = true;
}
}
return result;
}
/**
* AbstractCollection中默认不支持添加单个元素,如果直接调用会报错
*@Description:默认是抛出异常,都是让子类去实现
*/
public boolean add(E e) {
throw new UnsupportedOperationException();
}
// 实现在集合中添加一个集合
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
// 获取待添加对象的迭代器
Iterator<? extends E> it = c.iterator();
// 挨个遍历,如果add()没有实现的话,addAll()也不会实现
while(it.hasNext()) {
if(add(it.next())){
modified = true;
}
}
}
// 实现清空集合
public void clear() {
// 获取子类实现的迭代器,挨个遍历删除
Iterator<E> it = iterator();
while(it.hasNext()) {
it.next();
// 单线程使用迭代器的remove()方法不会导致fail-fast
it.remove();
}
}
/**
* 实现集合转换成数组
*@Description:这里返回的顺序和Iterator顺序一致,在这里实现是方便实现类互相转换
*/
// 先根据当前集合大小声明一个数组
public Object[] toArray() {
// 集合元素的大小赋值给数组大小后,可能会存在同步线程修改集合
Object[] object = new Object[size()];
Iterator<E> it = iterator();
// 迭代器师集合的迭代器,但最多访问的位置是数组的大小位置,如果没有访问到数组的大小位置,则表明集合元素减少了
for(int i = 0; i < object.length; i++) {
// 集合元素没有数组那么多,说明不需要那么大的数组
if(!it.hasNext()) {
// 这里很明显是静态方法
// 扩容的主要手段是Arrays.copyOf()方法,即新建一个原数组的拷贝,并修改原数组,指向这个新建数组。原数组自动抛弃(java垃圾回收机制会自动回收)
return Arrays.copyOf(object,i);
}
// 将集合元素赋值给数组
object[i] = (Object) it.next();
}
// 元素比从SIZE()中获取的更多,就需要进一步调整数组的大小
return it.hasNext() ? finishToArray(object,it) : object;
}
// 跟上一个转换数组相比,通过传入指定类型的数组可以明确返回数组的类型
@SuppressWarnings("unchecked") // 这里是注解
public <T> T[] toArray(T[] a) {
// size就是集合的大小
int size = size();
// 当传入数组的大小大于集合的大小时,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++) {
// 如果迭代器到最后了,数组还未满,则说明集合数据减少了
if (! it.hasNext()) {
if (a == r) {
// 如果传入的数组恰好是r数组,直接就返回a数组
r[i] = null;
} else if (a.length < i) {
// 传入的数组长度小于当前r数组有元素的长度,则只需要去掉r数组有null部分的长度
return Arrays.copyOf(r, i);
} else {
// 传入的数组长度大于等于r数组,把r数组赋值给a数组,若没填满,则剩余长度赋值为null,然后返回a数组
System.arraycopy(r, 0, a, 0, i);
if (a.length > i) {
a[i] = null;
}
}
return a;
}
r[i] = (T)it.next();
}
// 当集合元素获取迭代器后数据变多了,则将剩余的元素传入finishToArray()方法填入新的数组中,当获取迭代器后数量不变,则将数据赋值给r数组,并返回r数组
return it.hasNext() ? finishToArray(r, it) : r;
}
// 进一步调整数组的大小
private static <T> T[] finishToArray(T[] object,Iterator<?> it) {
// 记录当前大小
int len = object.length;
int i = len;
while(it.hasNext()) {
// 数组长度不够,继续分配
if(i == len) {
// 按Object长度的1.5倍进行扩容
len = ArraysSupport.newLength(len,1,(len>>1)+1);
// 对object数组进行扩容
object = Arrays.copyOf(object, len);
}
// 赋值,进入下一轮循环
object[i++] = (T) it.next();
}
// 由于之前扩容是1.5倍进行的,最后将其设置到和object实际需要的相同
return (i==len)?object:Arrays.copyOf(object, i);
}
/**
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
// 超过了最大容量,MAX_ARRAY_LENGTH=Integer.MAX_VALUE-8
if (newLength - MAX_ARRAY_LENGTH <= 0) {
return newLength;
}
return hugeLength(oldLength, minGrowth);
}
private static int hugeLength(int oldLength, int minGrowth) {
int minLength = oldLength + minGrowth;
if (minLength < 0) {
throw new OutOfMemoryError("Required array length too large");
}
if (minLength <= MAX_ARRAY_LENGTH) {
return MAX_ARRAY_LENGTH;
}
return Integer.MAX_VALUE;
}
*/
/**
*@Description:toString()通过StringBuilder拼接了每个元素的toString完成的
*/
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
// 无限循环
for (;;) {
E e = it.next();
// 避免在集合中出现a.add(a)导致无限循环调用toString()导致堆溢出
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
// 调用StringBuilder自身的toString()完成打印
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
}
集合类源码之AbstractCollection(二)
最新推荐文章于 2021-12-04 11:44:50 发布