共同学习Java源代码--数据结构--AbstractCollection抽象类(一)

这是Collection接口的一个直接实现类,大家熟知的ArrayList也是继承自AbstractList,而后者继承了这个类。

public abstract class AbstractCollection<E> implements Collection<E> 

这是该类的签名,实现了Collection接口。

    protected AbstractCollection() {
    }

这是构造方法。

 public abstract Iterator<E> iterator();

这是获取迭代器的方法。

 public abstract int size();

这是获取元素数量的方法。

    public boolean isEmpty() {
        return size() == 0;
    }

这个方法是判断集合是否为空的方法,为具体实现方法。

    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;
    }

这个方法是判断集合是否存在某元素的方法。

首先获取迭代器。然后判断参数是否为空,如果为空则迭代元素找到·1为空的元素为止返回true。如果参数不为空,则同样开始迭代,调用参数的equals方法进行判断直到找到相等的元素为止返回true。

如果迭代后仍然没有返回,则直接返回false。

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

这个静态final的成员变量代表的是元素最大长度,也就是Integer最大值减八。

    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;
    }

这个方法是转换成数组的方法。

首先定义一个Object数组r,长度为size方法的返回值。然后定义一个迭代器。

然后进入for循环,按照r数组长度遍历r,先判断迭代器是否完毕,如果迭代完毕,就将r拷贝到新数组里并返回,新数组的长度就是当前遍历的数组下标。

然后将数组的每一个元素赋值为迭代器的下一个值。

如果数组遍历完成,但迭代器仍然还有元素没有迭代完,那就进入finishToArray方法,否则返回r。

    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);
    }

这个方法先创建变量i初始值为r的长度。

然后继续迭代。每次迭代都要先创建变量cap,赋值为r的长度,因为r的长度会变。如果i和cap相等也就是r的初始长度和迭代开始时的长度相等,那么创建变量newCap,值为cap加上cap右移一位也就是cap的2倍,再加上1。

如果newCap大于数组最大长度,那么newCap赋值为hugeCapacity方法的返回值。然后将r拷贝到新的数组里,其长度是newCap。然后继续迭代,放入扩容后的r中。

最后判断变化后的i,也就是数组长度的变化值是否等于数组的真实长度,如果不等于,就将数组的容量改回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;
    }

这个方法先判断参数是否小于零,否则抛出error。最后判断参数如果大于最大数组长度,就返回int类型的最大长度。

    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);
        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。首先创建变量size,获取元素长度。

然后创建泛型数组r,判断如果参数a的长度大于本集合对象的元素长度。则将a的引用给r,否则用Array类创建数组实例,长度为size。

然后获取迭代器。

然后开始遍历数组r。

先判断是否遍历完成,如果遍历没完成,则将r元素赋值为迭代器迭代的下一个元素,并进行强制类型转换。如果遍历完成,继续进行判断,如果参数a和r是一个对象,则将当前遍历的i下标元素设为空,也就是说之前a的引用给了r,a长度大于r的长度(也就是本集合的长度)的话,如果迭代器迭代完毕,再给a的剩余元素中设一个null值;如果a的长度小于正在遍历的下标i,则将r拷贝到新数组里并返回这个新数组,新数组长度为正在遍历的下标i,也就是说之前a的引用没有给r,r是新建数组长度为本集合的长度,a的长度小于本集合的长度(也就是r的长度),也小于正在遍历的i下标的值,则将r拷贝到一个新数组并返回,新数组长度为i,因为i永远小于本集合的长度,此时a的长度小于i小于r的长度和本集合长度;如果a的引用没有给r,也就是a的长度小于r的长度和本集合长度的情况下,且a的长度大于等于正在遍历的i的长度,则将r拷贝到a,拷贝的长度为i,此时i小于a的长度小于r的长度和本集合的长度。这个有点绕。因为集合长度和迭代器可以迭代的数量不是一回事,有时候迭代器可以迭代的数量小于集合长度。

最后跳出for循环后判断是否还可以迭代,如果还可以迭代就调用上面那个方法,否则返回r。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值