java集合分析(4):AbstractCollection
来源:互联网 发布:网络捕鱼游戏原理 编辑:程序博客网 时间:2024/06/05 05:57
在上一篇中我们学习了Collection的基本概念和用法,这篇我们来看看实现了Collection接口的抽象类AbstractCollection。
AbstractCollection
直接实现Collection接口的类只有AbstractCollection类,该类是一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类;
如果想要实现一个不可修改的Collection,只需要继承AbstractCollection并且实现两个抽象方法即可;
如果想要实现可以修改的Collection,还需要重写add()方法和iterator()方法返回的迭代器实现remove()方法;
下面我们来看看AbstractCollection内部的具体实现:
public abstract Iterator<E> iterator(); public abstract int size();
可以看到这两个是抽象方法,没有具体实现,让子类去复写。
isEmpty
public boolean isEmpty() { return size() == 0;}
直接调用size()(这个size()在AbstractCollection中是空实现,具体实现是在子类中)方法返回大小,如果是0就认为是空集合.
contains
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; }
从上面contains源码可以看到 , contains方法里是先调用自己iterator(这个iterator在AbstractCollection中是空实现,具体实现是在子类中)方法来遍历集合,并且是先判断传来的参数是否null.然后在做具体的实现.
toArray()
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; }
从上面源码可以看到,内部实现是先根据size()的大小生成一个数组,然后获取Iterator迭代器, 在通过hasNext来判断当前迭代器后面还有没有值,如果有就赋值给数组 r;
if (! it.hasNext())这段代码判断当前迭代器实际迭代数量的大小比size()小,如果成立, 就直接通过Arrays.copyOf来复制当前数组r,然后直接返回;
通过上面for循环之后,如果if (! it.hasNext())不成立,那么r数组的大小就是size大小,但最后这段代码 [return it.hasNext() ? finishToArray(r, it) : r],意思是如果当前迭代器it.hasNext()后面还有值,也就是size的大小小于迭代器迭代的数量 , 就调用finishToArray来完成之后迭代器的实现,否则就直接返回数组 r .
finishToArray
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); }
我们可以看到每次进入循环体,先用cap确认下数组的长度。如果i还没有增长到cap相同的程度则只要将迭代器的下一个元素放入数组并将i加一就行; 如果i==cap的时候说明需要增大cap。这里增加的cap的一半并加1的大小,然后判断下新的数组的大小是否超过VM的最大界限,如果没有就将继续循环体; 在返回的时候使用根据已经迭代的元素i来复制当前数组到一个新的数组中 ; 这里如果判断newCap大小超过了最大的数组大小则调动hugeCapacity调整大小。这里需要说明在AbstractCollection类中间声明了一个静态私有常量MAX_ARRAY_SIZE数值为Integer.MAX_VALUE - 8。按照源码里的说明是虚拟机通常会放几个头信息在数组中。
hugeCapacity
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; }
如果当前的cap最大值不可在继续增大,即cap+1为负值则抛出一个超出内存大小的异常。
如果当前的值可以分配,则分配一个MAX_ARRAY_SIZE和MAX_VALUE 中的满足条件的值。
remove() 删除某个元素:
public boolean remove(Object o) { Iterator<E> it = iterator(); if (o==null) { while (it.hasNext()) { if (it.next()==null) { it.remove(); return true; } } } else { while (it.hasNext()) { if (o.equals(it.next())) { it.remove(); return true; } } } return false; }
removeAll() 删除指定集合中包含在本集合的元素:
public boolean removeAll(Collection<?> 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) { boolean modified = false; Iterator<E> it = iterator(); while (it.hasNext()) { if (!c.contains(it.next())) { it.remove(); modified = true; } } return modified; }
toString() 把内容转换成一个 String 进行展示:
public String toString() { if (isEmpty()) { return "[]"; } //注意默认容量是 size() 的 16 倍,为什么是 16 呢? StringBuilder buffer = new StringBuilder(size() * 16); buffer.append('['); //仍旧用到了迭代器 Iterator<?> it = iterator(); while (it.hasNext()) { Object next = it.next(); if (next != this) { //这个 Object 也得重写 toString() 方法,不然不能输出内容 buffer.append(next); } else { buffer.append("(this Collection)"); } if (it.hasNext()) { buffer.append(", "); } } buffer.append(']'); return buffer.toString();}
ArrayList<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); System.out.println(list);
输出结果:[a, b, c]
可以看出System.out.print(list) 直接输出集合的全部内容,而不用挨个遍历输出,全是因为 AbstractCollection 的toString() 方法。
add(E e)
public boolean add(E e) { throw new UnsupportedOperationException(); }
可以看出,AbstractCollection 中默认不支持添加单个元素,如果直接调用 add(E) 方法,就会报错,因此,如果子类是可添加的数据结构,需要自己实现 add(E) 方法。
addAll 添加一个集合内的全部元素:
public boolean addAll(Collection<? extends E> c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; }
Thank:
http://blog.csdn.net/u011518120/article/details/51924587
- java集合分析(4):AbstractCollection
- Java集合之AbstractCollection
- java 集合框架-AbstractCollection
- Java AbstractCollection源码分析
- 源码分析-java-AbstractCollection
- java集合系列03 AbstractCollection
- java的AbstractCollection源码分析
- Java集合类源码阅读之AbstractCollection
- java集合源码解析(二)--AbstractCollection
- Java 集合深入理解(5):AbstractCollection
- Java集合类:AbstractCollection源码解析
- Java 集合深入理解(5):AbstractCollection
- Java 集合深入理解(5):AbstractCollection
- java利用AbstractCollection实现自己的可迭代集合类
- 解析java.util集合类源码(Collection和AbstractCollection篇)
- AbstractCollection源码分析
- AbstractCollection 源码分析
- java.util.AbstractCollection翻译
- ubuntu16.04+caffessd(cpu版)+python接口安装
- Spark Streaming Quick Start
- 面向对象之封装、继承和多态
- Linux安装Memcached服务端
- Https双向认证Android客户端配置
- java集合分析(4):AbstractCollection
- Linux安装Tomcat及JDK
- 解决百度云盘限速问题
- 第一天--入职
- 什么是AngularJS及优点总结!
- Java知识点总结(四)泛型和集合
- WorldWideWeb浏览器
- 电脑断电重启不正常
- 最长公共子序列 + 记录路径 ( 51 NOD DP 教程 )