彻底理解容器类(2)------- AbstractCollection深入了解
h2 { background-color: Skyblue }
AbstractCollection认识
AbstractCollection是Collection接口的抽象实现。实现了一部分Colleciton,并且添加了几个新的方法。

源码之前的预热
在进行AbstractCollection源码阅读前,先看看AbstractCollection中使用到的一些其他源码
- System.arraycopy(Object src, int srcPos, Object dest, int destPos,int length);
- Arrays.copyOf(T[] original, int newLength)
1. System.arraycopy是Native方法,是java的本地方法,是用其他语言写的。所以我们是看不到更底层的代码的。但是native方法一般会比你自己写的效率更好。这个方法的作用是从src中复制(srcPos位置到srcPos+length-1位置)的元素到dest的destPos到destPos+length-1的位置。
System.arraycopy(Object src, int srcPos, Object dest, int destPos,int length);
src: source 代表源数组
srcPos: source position 代表源数组起始的位置
dest: destination 代表目标数组。
destpos: destination position 目标数组的起始位置
length: length 复制的元素个数
src和dest可以是同一个数组
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
2.Arrays.copyOf(T[] original, int newLength)
Arrays.copyOf(U[] original, int newLength, Class<? extends T[]> newType)
这个方法返回一个T[].
original: 被复制的数组
newLength: 返回的新的数组的长度
newType: 返回的数组的类型(比如说String[]的数组还是Integer[]的数组),注意所有的数组的父类都是Object[]。
@SuppressWarnings("unchecked")
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] // newtype如果是Object类型的话就创建一个Object[]的数组
: (T[]) Array.newInstance(newType.getComponentType(), newLength); //否则就创建一个特定类型的数组, newInstance是native方法创建一个具体类型的数组
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength)); //然后把源数组移动到目标数组中.
return copy;
}
源码分析
1.类的声明,实现了Collection接口
public abstract class AbstractCollection<E> implements Collection<E> {}
2.构造器方法
protected AbstractCollection() {} //protected 修饰说明只对子类或者同一个包下类可见
3. 抽象方法
public abstract Iterator<E> iterator(); 抽象方法未实现
public abstract int size(); 抽象方法未实现
4. 判断是否为空
public boolean isEmpty() { //通过判断size是否等于0判断这个容器是否为空
return size() == 0;
}
5. 判断是否包含某个元素
public boolean contains(Object o) {
Iterator<E> it = iterator(); //得到一个迭代器
if (o==null) { //如果传进来是null就通过迭代器一个个对比是否是null,是null的话就返回true
while (it.hasNext())
if (it.next()==null)
return true;
} else { //如果传进来不是null就通过迭代器使用equals方法比较
while (it.hasNext())
if (o.equals(it.next())) //如果equals方法比较true,则返回true
return true;
}
return false; //没有相等的情况返回false
}
6. 通过容器的迭代器返回一个Object数组
public Object[] toArray() {
Object[] r = new Object[size()];
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) // fewer elements than expected 比预期的元素个数少的话就通过 Arrays.copyOf生成一个个数正好相等的Object数组
return Arrays.copyOf(r, i);
r[i] = it.next(); //把迭代器中的元素的引用赋值给数组
}
return it.hasNext() ? finishToArray(r, it) : r; //迭代器元素个数比size的话,返回finishToArray(r, it), 否则直接返回对象。
}
7. 迭代器中的剩余的元素全部放入数组中
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; MAX_ARRAY_SIZE; //是最大的数组容量
@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; //每次容量增加2分之一
if (newCap - MAX_ARRAY_SIZE > 0) // 能自动感知到容量是否超出了虚拟机允许的数组的容量,
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap); //r赋值成新的对象数组对象,这个对象的大小是newCap(new Capacity)
}
r[i++] = (T)it.next(); //i自增,并且赋值新的元素
}
// trim if overallocated 如果数组容量有余的话,就把数组修剪成正好的容量
return (i == r.length) ? r : Arrays.copyOf(r, i);
}
//重新给一个大小因为cap + (cap >> 1) + 1可能会超过int的最大值,或者超过数组的长度的最大值
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;
}
8.add方法,不支持add方法
public boolean add(E e) {
throw new UnsupportedOperationException();
}
9 移除一个元素
public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o==null) { //null的话通过判断是不是null是的话直接返回true
while (it.hasNext()) {
if (it.next()==null) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) { //遍历迭代器
if (o.equals(it.next())) { //如果有对象相等的话就返回
it.remove(); //并且通过迭代器来消除对象 (迭代器不一定实现了消除,比如可能迭代器的消除会抛出一个UnsupportedOperationException())
return true;
}
}
}
return false;
}
10. 是否包含所有的传入参数中的元素
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e)) //只要有一个没有包含就直接返回false
return false;
return true;
}
11.增加所有的元素到容器中
public boolean addAll(Collection<? extends E> c) {
boolean modified = false; //modified 代表是否修改过元素
for (E e : c) //遍历参数容器,add方法加入容器
if (add(e))
modified = true;
return modified;
}
12.移除全部
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c); //C是null的话就抛出异常
boolean modified = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) { //遍历c容器,如果c包含一个元素,就把那个元素给remove掉
it.remove();
modified = true;
}
}
return modified;
}
13.移除全部元素
public void clear() {
Iterator<E> it = iterator();
while (it.hasNext()) {
it.next();
it.remove(); //迭代器一个一个消除
}
}
14. toString方法
public String toString() {
Iterator<E> it = iterator(); //如果没有包含元素返回[]
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e); //e == this 用来防止死循环
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
总结:AbstractCollection只是给其他类使用的一个模板,要成为一个能够工作的容器还需要很多方法和存储的元素对象。
彻底理解容器类(2)------- AbstractCollection深入了解的更多相关文章
- Java编程的逻辑 (52) - 抽象容器类
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- 走进Java中的持有对象(容器类)之一 容器分类
Java容器可以说是增强程序员编程能力的基本工具,本系列将带您深入理解容器类. 容器的用途 如果对象的数量与生命周期都是固定的,自然我们也就不需要很复杂的数据结构. 我们可以通过创建引用来持有对象,如 ...
- Java中的泛型 (上) - 基本概念和原理
本节我们主要来介绍泛型的基本概念和原理 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以 ...
- setAction方法 Snackbar 右侧按钮可以被点击并处理一些事件
从数据库同一记录取得的字段所组装成的对象应该是同一个对象,然后由不同的Session从数据库同一条记录上分别取得对象,它们的内存地址是不一样的. 一般来说,常见的数字加密方式都可以分为两类,即对称加密 ...
- 黑马程序员:3分钟带你读懂C/C++学习路线
随着互联网及互联网+深入蓬勃的发展,经过40余年的时间洗礼,C/C++俨然已成为一门贵族语言,出色的性能使之成为高级语言中的性能王者.而在今天,它又扮演着什么样重要的角色呢?请往下看: 后端服务器,移 ...
- 【转】Java基础——容器分类
Java容器可以说是增强程序员编程能力的基本工具,本系列将带您深入理解容器类. 容器的用途 如果对象的数量与生命周期都是固定的,自然我们也就不需要很复杂的数据结构. 我们可以通过创建引用来持有对象,如 ...
- Java编程的逻辑 (35) - 泛型 (上) - 基本概念和原理
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- C++学习路线(转载)
随着互联网及互联网+深入蓬勃的发展,经过40余年的时间洗礼,C/C++俨然已成为一门贵族语言,出色的性能使之成为高级语言中的性能王者.而在今天,它又扮演着什么样重要的角色呢?请往下看: 后端服务器,移 ...
- 8、泛型程序设计与c++标准模板库1、泛型程序设计的概念和术语
有效地利用已有的成果,将经典的.优秀的算法标准化.模块化,从而提高软件的生产率,是软件产业化的需求,为了实现这一需求,不仅需要面向对象设计思想,而且需要泛型程序设计思想. c++语言提供的标准模板库( ...
随机推荐
- python之字典常用语法
1. 创建字典 描述:生成字典 语法: dic={'k1':'v1'} 样例: dic=dict(k1='v1',k2='v2') dic={'k1':'v1','k2':'v2'} 2. 取键值ge ...
- Wpf中鼠标样式的修改,作用点修改
最近,在做一个控件的鼠标样式,Ps加了插件,可以编辑生成.cur格式的图标. 可是,所有的改完以后,调试运行,结果发现自己制作的图标的作用点总是在左上角,而不是在"手形"图标的食指 ...
- 给ubuntu安装VNC远程桌面
(只有背景,没有菜单栏问题没有解决)Virtual Network Computing(VNC)是进行远程桌面控制的一个软件.客户端的键盘输入和鼠标操作通过网络传输到远程服务器,控制服务器的操作.服务 ...
- Linux下ifort的安装记录
首先进入网址https://software.intel.com/en-us/qualify-for-free-software/student 下载Intel Parallel Studio XE ...
- 初探Lambda表达式/Java多核编程【3】Lambda语法与作用域
接上一篇:初探Lambda表达式/Java多核编程[2]并行与组合行为 本节是第二章开篇,前一章已经浅显地将所有新概念点到,书中剩下的部分将对这些概念做一个基础知识的补充与深入探讨实践. 本章将介绍L ...
- BZOJ 3083: 遥远的国度(树链剖分+DFS序)
可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...
- 走进javascript——解开switch之谜
很早以前就觉得switch很怪异,或者说一直没太理解它,它怪异就怪异在非要给每个语句加上break;不然后面的语句就算不符合条件还是会执行,比如以下这段代码 var num = 2; switch(n ...
- SQL中的join连接查询
inner join(交集 ,自然连接, 简写成join) 是最普通的连接查询,相当于早期根据where条件连接的查询 outer join(并集或部分并集,左表 + 右表) le ...
- Tomcat8 + Redis实现session集中管理
环境准备: 部署两台 tomcat 8.0 安装 redis 服务器 下载工具库( commons-pool2-2.3.jar.jedis-2.7.2.jar .改良版的 tomcat ...
- 【《Effective C#》提炼总结】提高Unity中C#代码质量的21条准则
作者:Williammao, 腾讯移动客户端开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/290.h ...