HashSet、AbstractCollection中toArray()方法的分析

目录

问题描述 

我的分析:

问题描述 

  1. 遍历中为什么不是遍历迭代器?
  2. 为何要判断! it.hasNext() 然后返回Arrays.copyOf(r, i);
  3. 最后返回时为何要使用三目运算it.hasNext() ? finishToArray(r, it) : r;
   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;
    }

我的分析:

正常流程

  1. 创建了一个与set同样大小的Object数组Object[] r = new Object[size()]; 
  2. 获取迭代器;Iterator<E> it = iterator();
  3. 以数组的长度为指标进行for循环向数组r中添加元素
  4. 三目运算set中没有数据返回r数组
 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;

非正常流程,例如:多个线程操作该集合

  1. 如果 Object[] r = new Object[size()]之后Iterator<E> it = iterator();之前, set新增了内容。那么 set的大小将大于r的长度给r赋值的时候回报越界异常,因此不用迭代器循环
  2. 同样set中新增了内容,循环完成之后需要使用it.hasNext()判断,还有数据于是使用finishToArray()方法,增加r的大小继续向r中新增数据。
  3. 如果 Object[] r = new Object[size()]之后Iterator<E> it = iterator()之前, set删除了内容,那么 set的大小将小于r的长度,此时还未循环完成 set中已经没了数据,所以在循环中需要何要判断! it.hasNext()判断, 然后使用Arrays.copyOf(r, i),新创建一个新的数组返回。

通过以上方法可以保证返回的数据与set中一致。其他情况,例如在Iterator<E> it = iterator()之后set的值发生变换,应该会发生java.util.ConcurrentModificationException异常

finishToArray方法

    @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);
    }
  1. 将r的长度赋值给i,int i=r.length;
  2. while遍历迭代器;
  3. 将r的长度赋值给cap,int cat = r.length;
  4. 判断i与cap是否相等,如果相等,创建一个新的长度 newcap = cap+(cap>>1)+1(新增cap的一半加1)
  5. 判断newCap与MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8)的大小,如果newCap大于Integer.MAX_VALUE - 8 则返回新的值。
  6. 复制r中的数据到r中,并增加r大小 r = Arrays.copyOf(r, newCap),此时 r 的长度大于 i;
  7. 将下一个数据新增到r中r[i++] = (T)it.next();并将 i 加1,保证 i 是数据的实际长度
  8. 遍历完成之后 判断 i (数据的实际长度)与此时 r 的长度(数组的大小),如果相等,则返回 r 本身,如果r的长度更大则通过Arrays.copyOf(r, i); 返回一个大小为 i 的数组。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值