目录
问题描述
- 遍历中为什么不是遍历迭代器?
- 为何要判断
! it.hasNext() 然后
返回Arrays.copyOf(r, i);
最后返回时为何要使用三目运算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;
}
我的分析:
正常流程
创建了一个与set同样大小的Object数组Object[] r = new Object[size()];
获取
迭代器;Iterator<E> it = iterator();
- 以数组的长度为指标进行for循环向数组r中添加元素
- 三目运算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;
非正常流程,例如:多个线程操作该集合
- 如果
Object[] r = new Object[size()]
之后Iterator<E> it = iterator();之前,
set新增了内容。那么 set的大小将大于r的长度给r赋值的时候回报越界异常,因此不用
迭代器循环。
同样set中新增了内容,循环完成之后需要使用it.hasNext()判断,还有数据于是使用finishToArray()方法,增加r的大小继续向r中新增数据。
- 如果
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);
}
- 将r的长度赋值给i,int i=r.length;
- while遍历迭代器;
- 将r的长度赋值给cap,int cat = r.length;
- 判断i与cap是否相等,如果相等,创建一个新的长度 newcap = cap+(cap>>1)+1(新增cap的一半加1)
- 判断newCap与MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8)的大小,如果newCap大于Integer.MAX_VALUE - 8 则返回新的值。
- 复制r中的数据到r中,并增加r大小 r = Arrays.copyOf(r, newCap),此时 r 的长度大于 i;
- 将下一个数据新增到r中r[i++] = (T)it.next();并将 i 加1,保证 i 是数据的实际长度
- 遍历完成之后 判断 i (数据的实际长度)与此时 r 的长度(数组的大小),如果相等,则返回 r 本身,如果r的长度更大则通过Arrays.copyOf(r, i); 返回一个大小为 i 的数组。