AbstractCollection

AbstractColletion源码分析

简介

AbstractCollection直接实现了Collection接口,我们来了解一下。

API

1543329405289

如图可知除了finishToArray(T[],Iterator<?>),hugeCapacity以及受保护的构造方法,其他都是继承自Collection以及Object,并给与实现,如果不清楚Collection接口的小伙伴,可以先去阅读上篇Collection接口再来继续下面的内容。

源码分析

  • 返回迭代器,交于子类去实现
public abstract Iterator<E> iterator();
  • 返回长度,交于子类去实现
public abstract int size();
  • 判断是否为空
public boolean isEmpty() {
    return size() == 0;
}
  • 判断是否包含某个元素

    1:如果传进来的对象是null,则判断集合中是否包含null

    2:如果传进来的对象不是null,则判断集合中是否有相同的元素

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 {
        // 表示O不为空 
        while (it.hasNext())
            if (o.equals(it.next()))
                return true;
    }
    return false;
}
  • 将集合转成Object[]

    1:返回一个数组,跟集合元素的顺序一样。

    2:如果迭代器返回的元素数量大于指定的数组,则分配新的数组(可能存在并发操作,导致集合元素元素变化)

    3:在这里会分两种情况:如果集合元素的长度最终小于等于分配的数组r的长度,那么调用Arrays.copyOf方法; 如果集合元素的长度大于分配的数组r的长度,也就是it.hasNext() ==true ,因为预期情况 当for循环完了之后,it.hasNext ==false, 当为true的时候,直接调用finshToArray方法重新分配r数组的容量,去容纳多余的集合元素。

public Object[] toArray() {
    // 新建一个Object[]数组 ,长度为集合长度
    Object[] r = new Object[size()];
	// 获取迭代器 
    Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        if (! it.hasNext())
            // 如果要复制的元素小于等于r数组的长度,调用Ayyarys.copyOf方法
            return Arrays.copyOf(r, i);
        r[i] = it.next(); // 指针后移
    }
    // 如果集合元素比预期的多,那么调用finshToArray,否则返回数组r
    return it.hasNext() ? finishToArray(r, it) : r;
}
  • 集合转Object[]
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    // 估计元素大小为集合元素的长度(并发操作会改变预估的大小)
    int size = size();
    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()) { // 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;
}
  • finishToArray (完成toArray的后续方法)

    1:当迭代器返回的元素多于预期时,重新分配在toArray中使用的数组容量,即创建一个新的数组,将原来数组的内容复制到新数组中,并追加集合新增的元素。

    2: 扩容的具体内容: hugeCapacity扩大数组最大容量。 之后再进行复制collection元素到数组里,此时的r就拥有了和newcap一样的容量, 然后r开始从i++(r之前的length往后开始添加新的元素) 但是估计一般不需要再次扩大数组容量, 当然这样设计也体现了设计的严密性。 最后看(i是最终元素量)有没有达到 扩展之后的长度, 假如正好,直接返回r数组,没有根据i的最终元素量截断。

@SuppressWarnings("unchecked")
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
    // 获取传进来的数组大小
    int i = r.length;
    // 判断是否还有元素(这里一个关键点,传进来的迭代器,指在哪里就是哪里的位置)
    // 所以it.hasNext()并不是第一个位置,而是传过来的下一个位置
    while (it.hasNext()) {
        int cap = r.length;
        if (i == cap) {
            int newCap = cap + (cap >> 1) + 1;
            // 判断数组是否溢出
            if (newCap - MAX_ARRAY_SIZE > 0)
                newCap = hugeCapacity(cap + 1);
            // 创建新的数组
            r = Arrays.copyOf(r, newCap);
        }
        r[i++] = (T)it.next();
    }
    return (i == r.length) ? r : Arrays.copyOf(r, i);
}
  • hugeCapacity

    判断是否溢出,溢出则抛出 OutOfMemoryError错误

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;
}
  • add - 添加方法(可选)
// 一个典型的可选方法,如果子类不实现,那么直接抛出异常UnsupportedOperationException
public boolean add(E e) {
    throw new UnsupportedOperationException();
}
  • remove - 移除某个元素
// 删除某个元素
public boolean remove(Object o) {
    Iterator<E> it = iterator();
   // 如果为null,循环判断并删除
    if (o==null) {
        while (it.hasNext()) {
            if (it.next()==null) {
               it.remove();
                return true;
            }
        }
    } else {
        // 不为null,循环判断是否等同元素
        while (it.hasNext()) {
            if (o.equals(it.next())) {
                it.remove();
                return true;
            }
        }
    }
    return false;
}
  • containsAll - 判断列表是否包含集合c的所有元素
// 判断列表是否包含集合中的所有元素
public boolean containsAll(Collection<?> c) {
   for (Object e : c)
        if (!contains(e))
            // 只要有一个不存在于列表就返回false
            return false;
    return true;
}
  • addAll - 将集合所有元素添加到列表中
// 将集合中的所有元素添加到列表中
public boolean addAll(Collection<? extends E> c) {
    // 标记是否修改
    boolean modified = false;
    for (E e : c)
        if (add(e))
            modified = true;
    return modified;
}
  • removeAll - 移除集合中存在于列表的所有元素
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()) {
        // 具体实现看子类,只是调用了Collection接口的方法
        // 如果包含c集合中的元素,则从列表中删除
        if (!c.contains(it.next())) {
            it.remove();
            modified = true;
        }
    }
    return modified;
}
  • clear 清空所有元素
// 删除所有元素
public void clear() {
    Iterator<E> it = iterator();
    while (it.hasNext()) {
       it.next();
        it.remove();
    }
}
  • toString 将列表转成字符串
// 把列表转成String
public String toString() {
    Iterator<E> it = iterator();
    // 如果空集合则返回"[]"
    if (! it.hasNext())
        return "[]";
	// Stringbuilder连接字符串
    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(' ');
    }
}

Arrays.copyOf和System.arraycopy

1: 判断类型是否相匹配,如果匹配则直接新建数组,如果不匹配通过反射新建数组
2:Arrays.copyof底层调用的是System.arraycopy()方法

3:native指的是本地方法,在这里的arraycopy是由C++实现的

public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
@param <U> 原始数组中对象的类
@param <T> 返回数组中对象的类
@param original 要被复制的原始数组
@param newLength 要返回的数组的长度
@param newType 要返回的对象数组的类型
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        // getComponentType 用来获取对象数组的class对象,非数组类型不可通过getComponentType来获取class对象。
        // 根据原始数组传过来的类型进行判断,返回类型相同的对象数组
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        // 调用System.arraycopy来完成数组拷贝功能
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }
  
 // System.arraycopy方法
@Param src - 源数组。
@Param srcPos - 源数组中的起始位置。
@Param dest - 目标数组。
@Param destPos - 目标数据中的起始位置。
@Param length - 要复制的数组元素的数量。
// 将指定源数组中的数组从指定位置开始复制到目标数组的指定位置
public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mindcarver

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值