博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java容器类研究3:AbstractCollection
阅读量:6002 次
发布时间:2019-06-20

本文共 4725 字,大约阅读时间需要 15 分钟。

ArrayList继承自AbstractList,AbstractList为“random access”的数组提供了基本的实现。随机访问数据是相对于顺序访问数据而言,例如链表的形式。AbstractSequentialList为链表形式的顺序访问提供了基本实现。AbstractList提供了默认的随机访问数据的iterator。AbstractList继承自AbstractCollection,AbstractCollection为Collection提供了基本实现。

java.util.AbstractCollection

<!--more-->

contains

AbstractCollection实现了查询是否包含某一个元素的方法。最好使用Iterator遍历集合中的元素,因为可以屏蔽集合内部元素存储的具体实现,并且根据不同的数据存储特点,优化访问策略。这里还可以正确查找null元素,需要注意的是对null元素的查询需要特别的处理,有时候自己实现方法时,往往会忽略传入参数为null时的处理,导致方法无法处理特殊情况。

public boolean contains(Object o) {        Iterator
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; }

toArray

toArray方法将容器中的元素转化为数组的形式。这里元素的复制,采用的是直接复制引用。这里还考虑到了并发运算时,元素数量在复制时产生变化的情况,当数量减少时,就用Arrays.copy()截取结果。当数量增加时,会调用finishToArray函数扩容。

public Object[] toArray() {        // Estimate size of array; be prepared to see more or fewer elements        Object[] r = new Object[size()];        Iterator
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; }

在finishToArray函数中,对容量每次扩展1/2+1的大小,并且会检查是否会超过设定的最大数组长度MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8。如果长度超过了限定值,则以原容量+1为底线,返回一个最大容量。最后返回的数组也会修剪掉多余的位置。

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

这里有一个toArray的重载,需要传入一个数组作为参数,据我观察,目的是将集合中的元素存入指定的数组,重利用已有数组的存储。如果元素过多,而目标数组容纳不下,只能重新申请数组来进行存储。

public 
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
it = iterator(); for (int i = 0; i < r.length; i++) { if (! it.hasNext()) { // fewer elements than expected if (a == r) { //利用的原数组,且元素不足,则补null表示结束 r[i] = null; // null-terminate } else if (a.length < i) { //元素较少,但数量超过原始数组,只能用新数组 return Arrays.copyOf(r, i); } else { //元素减少,导致原始数组可以容纳下,则copy回原始数组,折腾呗 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; }

removeAll

removeAll方法删除目标集合中的所有重叠元素。Iterator可以做到在遍历时,安全的删除元素,而通过index循环删除则可能导致index偏移。

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

toString

AbstractCollection的toString实现,比较令我震惊的是e == this的作用。这里为什么要判断打印的内容是否为自己本身?因为sb.append(e == this ? "(this Collection)" : e);会调用e的toString函数来生成字符串,若不加判断,则会形成无限的toString递归调用。我猜想一下,估计当时toString的实现者没有注意到该问题的存在,直到该bug出现,脑洞不大还真难想起来这个问题。

public String toString() {        Iterator
it = iterator(); if (! it.hasNext()) return "[]"; 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(' '); } }

转载地址:http://aadmx.baihongyu.com/

你可能感兴趣的文章
zabbix3.0 邮件报警配置
查看>>
全球15个顶级博客
查看>>
网红沈大师还是程大师,一个中肯的HCIE面试PASS
查看>>
自动化管理工具puppet
查看>>
我的友情链接
查看>>
访问 Neutron 外部网络 - 每天5分钟玩转 OpenStack(143)
查看>>
【Composer】实战操作二:自己创建composer包并提交
查看>>
CSS样式命名的重要性
查看>>
http 错误413
查看>>
让密码不再被遗忘 - 在web中尝试图形口令!
查看>>
Mysql 5.7.20 mysql innodb 系统表损坏带来的问题
查看>>
变更 Linux、Ubuntu 时区、时间
查看>>
java 金额转中文大写
查看>>
web系统如何设计登陆功能
查看>>
c语言实现数据结构中的队列
查看>>
电脑双击与右键打开菜单很慢
查看>>
python-27:如何获取多个页面的源码
查看>>
Access denied for user 'root'@'localhost'
查看>>
Protostar format1
查看>>
Scheme 'https' not registered
查看>>