我们查看Collection接口的hierarchy时候,可以看到AbstractCollection这样一个抽象类,它实现了Collection接口的部分方法,Collection集合系列的各个集合类都继承于该抽象类。我们来看看这个类:

public abstract class AbstractCollection implements Collection {

protected AbstractCollection() {

}

public abstract Iterator iterator();

public abstract int size();

public boolean isEmpty() {

return size() == 0;

}

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;

}

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;

}

@SuppressWarnings("unchecked")

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) {

r[i] = null; // null-terminate

} else if (a.length < i) {

return Arrays.copyOf(r, i);

} else {

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;

}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

@SuppressWarnings("unchecked")

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;

}

public boolean add(E e) {

throw new UnsupportedOperationException();

}

public boolean remove(Object o) {

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

}

public boolean containsAll(Collection> c) {

for (Object e : c)

if (!contains(e))

return false;

return true;

}

public boolean addAll(Collection extends E> c) {

boolean modified = false;

for (E e : c)

if (add(e))

modified = true;

return modified;

}

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;

}

public boolean retainAll(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;

}

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(' ');

}

}

}

从它的代码里我们可以看到,它有一个最大长度,是Integer的最大值减去8,至于为什么减8,是因为有些JVM会在数组里保存几个关键字符。我们再看这个contains方法,我很好奇的是,既然参数是Object类型,那么就包括了null,为什么判断的时候还要把null单独拿出来,这个疑问不知哪个大佬能给我解释一下。

再看toArray的不带参方法,new了一个和size()方法表示的长度一样长的Object数组r,还弄了一个迭代器出来,然后用for来循环r数组的每一个下标,并在每一次循环中判断迭代器的hasNext()是否为false,如果为false则说明当前集合长度比r数组短,则用Array的copyOf()方法把r数组放到一个长度为i的数组里,这样就不浪费多余的空间了。最后判断如果hasNext()还为true,则说明当前集合长度比r数组长,就用finishToArray()方法返回一个Object数组。至于为什么比较过和size()的大小之后还有这种操作,上面注释有说明,是迭代的时候假如对元素有增删操作,会导致长度有变化。finishToArray(T[] r, Iterator> it)方法把数组r扩容之后往里面添加迭代器后续元素,可以看到hugeCapacity这个玩意,当数组长度超过Integer最大值减8的时候,就用Integer的最大值,这样数组的长度是不能超过2^31的,毕竟数组下标使用int数字表示的。带参的toArray方法差不多意思,是可以将集合转化成指定类型的数组。

add()方法会直接抛出异常,说明AbstractCollection是不允许添加元素的,那么一定是在具体实现类里实现的这个方法。至于其他的方法,看一下就明白了。

接着我们来看看public abstract class AbstractList extends AbstractCollection implements List,这是list的抽象类,继承自AbstractCollection,实现List接口的部分方法。源码就不贴了,现在重点来看一下内部类Itr,这是一个迭代器的实现类。里面定义了三个变量:游标cursor、最近一次调用返回的索引lastRet和期望得到的修改次数expectedModCount。里面实现了迭代器的三个方法,注意next()和remove()方法里都调用了这么一个方法checkForComodification(),这个用来比较expectedModCount和modCount,如果不同就抛出异常ConcurrentModificationException,这个意思是如果在迭代操作的时候,如果有用非迭代器的操作对集合做了修改,那么就会抛出异常。对于modCount,我们可以在AbstractList的子类中看到,每次对集合做了操作,modCount就会加一。

public static void main(String[] args) {

List list = new ArrayList();

list.add(11);

list.add(12);

list.add(13);

list.add(14);

list.add(15);

Iterator itr = list.iterator();

while(itr.hasNext()) {

if(itr.next() == 13) {

itr.remove();

}

}

System.out.println(list);

}

在迭代的时候用迭代器的remove操作就不会报错,如果在增强for循环中,用了ArrayList自带的remove,就会报异常了。下面的内部类ListItr是一个ListIterator的实现类,可以往前往后迭代,还有多了几个方法,代码都很简单。subList()截取一段子序列,支持往前往后截取。下面还有个SubList类,里面有个往后截取一段子序列的方法,其他的起始都是用的父类的方法。

java集合类程序代码_java集合类源码学习二相关推荐

  1. java集合类程序代码_Java集合类源代码分析二:ArrayList(1)

    从java集合结构能够看出来ArrayList是属于Collection中的List范畴的.从源代码中是这样表示的, public classArrayList extends AbstractLis ...

  2. python程序代码解析_Python源码分析3 – 词法分析器PyTokenizer

    Introduction 上次我们分析了Python中执行程序可分为5个步骤: Tokenizer进行词法分析,把源程序分解为Token Parser根据Token创建CST CST被转换为AST A ...

  3. JAVA 单商户商城系统 成熟源码 支持二开

    三勾商城是开发友好的微信小程序商城,框架支持SAAS,支持发布 iOS + Android + 公众号 + H5 + 各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)等多个平台,不可多得的二开 ...

  4. 邮件 查看html源码,程序员跟着大师源码学习系列之2:查看网页和电子邮件的源码...

    在最近的文章中有大量电子邮件相关的内容,已经有不少同学上手发送了很多的邮件到我的测试邮箱中.坦率地说,有不少同学发送的电子邮件格式都是错误的 ... 那么抛开各种深奥地理论,有没有一种方法可以看看 1 ...

  5. 使用base标签后图片无法加载_Spring 源码学习(二)-默认标签解析

    `Spring` 解析默认标签~ 从上一篇笔记可以看出,在容器注册 bean 信息的时候,做了很多解析操作,而 xml 文件中包含了很多标签.属性,例如 bean . import 标签, meta ...

  6. ROS源码学习 二、线程池

    2021SC@SDUSC 目录 1.写在前面 2.ROS线程池概述 3.ROS线程池模型 4.ROS线程池源码详解 5.总结 1.写在前面 ROS作为一个操作系统,其职责是协调具有不同功能的node之 ...

  7. yara 源码学习(二) 规则编译部分

    yara规则的详细信息请参考: https://yara.readthedocs.io/en/stable/writingrules.html 根据官方文档,yara规则长这个样子: [1]:yara ...

  8. Box2d源码学习二内存管理之SOA的实现

    本系列博客是由扭曲45原创,欢迎转载,转载时注明出处,http://blog.csdn.net/cg0206/article/details/8258166 SOA,全称small object al ...

  9. Golang源码学习(二)----Go源码学习基础

    ### 本文源码版本为 GO 1.17.8 Windows/amd64: ### 可能参与对比的版本:GO 1.16.2 Linux/amd64一.Golang的编译器究竟是如何工作的? (学习源码有 ...

最新文章

  1. 很多人都在埋怨没有遇到好的团队,但好的团队不可能凭空出现,一流的团队不能仅靠团队成员努力,作为Leader,要有可行的规划,并坚定地执行、时势地调整(转)...
  2. (转)access和SQL语句的区别
  3. Android之四大组件概念讲解
  4. 100行的python作品详解_不到 100 行 Python 代码徐峥变葛优
  5. REM重复制造MFBF功能
  6. “互联网+”未来发展
  7. 解决Ajax异步请求中传数组参数,后台无法接收问题
  8. python处理多个excel数据_python 数据分析基础 day8-pandas读写多个excel文件
  9. MJRefresh自定义刷新动画
  10. 浅谈c++纯虚函数的多态与数据隐藏
  11. OPPO手机完美安装Kingroot实现一键root
  12. yolov3训练实现火焰检测(pytorch)
  13. 如何搭建个人服务器(网站/游戏)?
  14. 用MyDiskTest检测存储卡真实容量(图)
  15. Ant Design Pro从零到一(认识AntD)
  16. 世界各国2015-2020GDP排名
  17. openlayers 地图上加图标_OpenLayers学习笔记中级篇(四、地图图标操作)
  18. [Tips]Ubuntu20.04域名解析失败或网速很慢
  19. 易飞9安装和授权视频
  20. 关于bitset中的 to_ulong()的解答

热门文章

  1. 分享一套主流框架源码资料,征服阿里 P7 面试必备!
  2. 阿里云1C2G虚拟机【99/年】羊毛党集合啦!
  3. 【并发编程】Atomic与CAS
  4. No rule to make target ‘../../libxxx_lib.so‘
  5. python 模板匹配多个物体
  6. python numpy数组和one-hot编码相互转换
  7. python 调用C++,传递int,char,char*,数组和多维数组
  8. yolo类检测算法解析——yolo v3
  9. 文本处理相关资料整理
  10. src.checkVector(2, CV_32F) == 4 dst.checkVector(2, CV_32F) ==4