工作有几年了,说来惭愧,从来没认真仔细的分析过JDK里面的源码,从今天开始分析下JDK中集合部分源码,学习下大神的思路,如有错误,大家尽管指出。

JDK版本 JDK_1.8.0_201

编辑器:idea 2019.3

首先我们看一下Collection接口

java如何获取集合对象最大的值 java list 取最大值_迭代器

看一下Collection接口的各种关系,idea中 ctrl + h

java如何获取集合对象最大的值 java list 取最大值_迭代器_02

我们只看其中的Set与List

用一个UML图画一下

java如何获取集合对象最大的值 java list 取最大值_java如何获取集合对象最大的值_03

这里面有我们最常用到的ArrayList与LinkedList,以及HashSet 与LinkedHashSet

先看ArrayList类

java如何获取集合对象最大的值 java list 取最大值_迭代器_04

实现了四个接口、一个抽象类

java如何获取集合对象最大的值 java list 取最大值_字段_05

四个不可修改的变量

serialVersionUID:序列化需要的值
DEFAULT_CAPACITY :默认初始容量
EMPTY_ELEMENTDATA:用于空实例的共享空数组实例
DEFAULTCAPACITY_EMPTY_ELEMENTDATA:也是一个空的数组
elementData:真正存放元素的数组,用transient 关键字修饰?
size:元素个数

问题:为啥会有两个空的数组?transient 关键字?后续说明吧。

先看构造方法

java如何获取集合对象最大的值 java list 取最大值_java_06

1.指定大小的初始化方法,如果初始化数量等于0,elementData初始化为EMPTY_ELEMENTDATA数组,如果初始化入参小于0则抛出异常

2.不指定大小,默认空数组,elementData初始化为DEFAULTCAPACITY_EMPTY_ELEMENTDATA

3.将集合转为ArrayList

java如何获取集合对象最大的值 java list 取最大值_java_07

4.trimToSize方法

首先说明下modCount的作用,唉,看个源码有这么多东西需要学习。。。。。

看下官方解释,来自AbstractList中

java如何获取集合对象最大的值 java list 取最大值_迭代器_08

噼里啪啦一大堆,看滴脑阔痛。

原文大概意思:

这个字段表示list被结构性更改的次数,结构性更改是指改变了list的长度大小或者以别的方式干扰了这个值,会导致在迭代的过程中产生不正确的结果。

此字段由迭代器和列表迭代器实现使用,在next、add、remove、previous、set操作中如果此字段的值意外更改,则迭代器(或列表迭代器)将在其中抛出{ConcurrentModificationException}异常(阿里巴巴java开发手册关于list的遍历删除的规范有说明)面对迭代期间的并发修改,这提供了快速失败的行为,而不是不确定的行为

子类对于此字段的使用是可选择的,如果子类希望提供快速失败的迭代器(和列表迭代器)只需要在add、remove、等有可能结构性更改list的方法中增加这个字段的值。单线程调用add、remove方法不能删除正在遍历的对象。否则将可能抛出ConcurrentModificationException异常,如果子类不希望支持快速失败,该字段可以直接忽略。

阿里java开发手册

java如何获取集合对象最大的值 java list 取最大值_java_09

言归正传,这个方法平时基本上不会用到,第一次看到这个

java如何获取集合对象最大的值 java list 取最大值_字段_10

可以在debug的过程中查看这个变化过程

java如何获取集合对象最大的值 java list 取最大值_字段_11

初始化一个大小为10 的list,在list中添加了十个元素,这个时候可以看到elementData的数组大小是10,然后继续向下走,添加一个新元素,这个时候发现elementData的数组大小变为了15,这是它自动扩容了,这个时候的size的大小就不等于数组的大小了。继续走,把trimtosize方法走完,发现size的大小变的跟数组elementData的大小一样了。这就是这个方法的作用。

java如何获取集合对象最大的值 java list 取最大值_迭代器_12

既然讲到这了,先看一下它的add方法吧

java如何获取集合对象最大的值 java list 取最大值_迭代器_13

整体看起来比较简单,就是第一行调用了一个方法,我们来看看这个方法的内容,从字面的意思看是“确保内部容量”的意思。

java如何获取集合对象最大的值 java list 取最大值_数组_14

先看一下这个calculateCapacity计算容量的方法,在add之后会传size+1的值过来做计算

java如何获取集合对象最大的值 java list 取最大值_java如何获取集合对象最大的值_15

再看ensureExplicitCapacity方法,字面意思:“确保准确的容量”

java如何获取集合对象最大的值 java list 取最大值_字段_16

扩容方法

java如何获取集合对象最大的值 java list 取最大值_字段_17

数组最大值,为啥是int最大值-8?

  

java如何获取集合对象最大的值 java list 取最大值_java_18

16进制数据,转成10进制为2147483647,也就是2的31次方-1的值,也就是int的最大值

看看hugeCapacity方法对所需的最小容量值干了什么吧

java如何获取集合对象最大的值 java list 取最大值_数组_19

所以最大容量理论上可以达到Integer.MAX_VALUE的值,这已经是一个很大的数字了。

所以add一个元素的时候,如果实际元素数量大于数组的真实长度,那么就会执行扩容方法。

既然add讲完了,那么顺手看看get方法

java如何获取集合对象最大的值 java list 取最大值_字段_20

这个其实很简单啊,就是返回指定位置的数组的值就行。当然在返回值之前有一个判断方法rangeCheck

java如何获取集合对象最大的值 java list 取最大值_java_21

也就是如果指定的数组位置大于总大小,会抛出越界的异常

java如何获取集合对象最大的值 java list 取最大值_java如何获取集合对象最大的值_22

java如何获取集合对象最大的值 java list 取最大值_java如何获取集合对象最大的值_23

这个indexOf方法也很简单,返回指定元素在ArrayList中第一次出现的位置,同理,lastIndexOf返回最后一次出现的位置。

java如何获取集合对象最大的值 java list 取最大值_数组_24

返回一个副本的ArrayList集合

java如何获取集合对象最大的值 java list 取最大值_迭代器_25

上面这个也比较简单,给指定位置的ArrayList设置值

java如何获取集合对象最大的值 java list 取最大值_java_26

在判断是否需要扩容的同时将数组的length+1

java如何获取集合对象最大的值 java list 取最大值_数组_27

arraycopy方法,顾名思义,数组复制方法。做一个简单的演示

System.arraycopy(elementData, index, elementData, index + 1, size - index);

假如elementData现在存放的数据是{1,2,3,4,5},由于在判断是否扩容方法中重新构建过数组,这时的length是6,index = 3,由于那么执行这个方法的入参就是System.arraycopy(elementData, 3, elementData, 4, 2);最后得到结果是{1,2,3,4,4,5}。就是将数组的3位开始复制2位数据,从数组的第四位开始写进去,也就是{1,2,3,4}+{4,5}。

下面是删除方法,删除第几个元素

java如何获取集合对象最大的值 java list 取最大值_java_28

下面看删除指定元素方法

java如何获取集合对象最大的值 java list 取最大值_迭代器_29

阅读起来应该没有压力,看fastRemove方法

java如何获取集合对象最大的值 java list 取最大值_字段_30

与remove(int index) 方法大同小异,但是没有越界的校验,并且也没有返回要删除的值。(前面用到这个方法的删除方法,元素肯定在数组中,也就无需校验)

数组清空方法

java如何获取集合对象最大的值 java list 取最大值_java_31

将数组中是所有元素置为NULL,并且size置为0

下面看addAll方法,也比较简单

java如何获取集合对象最大的值 java list 取最大值_数组_32

从指定位置开始addAll,与addAll方法大同小异,不再详细说明,就贴个代码吧

java如何获取集合对象最大的值 java list 取最大值_字段_33

范围删除,从第几个元素开始删到第几个元素,也比较容易

java如何获取集合对象最大的值 java list 取最大值_迭代器_34

两个校验方法,这两个异常初学者应该见的比较多

java如何获取集合对象最大的值 java list 取最大值_迭代器_35

删除集合方法

java如何获取集合对象最大的值 java list 取最大值_字段_36

java如何获取集合对象最大的值 java list 取最大值_迭代器_37

这个方法里面设计的很巧妙,r!=size那块我觉得还是单独拿出来说明。正常流程r=size的流程应该还比较好懂

注释里面说了,如果c.contains()抛出异常,会导致r!=size

我们来做个实际例子,elementData={2,2,3,4,5,6} Collection c = {2,5,9},size = 6 

假如现在在判断c.contains(4)的时候报错,那么现在elementData={3,2,3,4,5,6} ,w = 1, r = 3,size=6

那么现在进入到r!=size 的if中,System.arraycopy(elementData, 3, elementData, 1, 3)的结果就是{3,4,5,6,5,6},w= w+ size -r = 4

然后继续执行w!=size的中的if内容 w = 4 从4开始的数据置为nul,修改size,修改modeifed = true。

总的来说这个方法看起来还是有点麻烦,但是用起来却没啥困难。写这个代码的人实在是大牛中的大牛。

java如何获取集合对象最大的值 java list 取最大值_迭代器_38

retainAll方法也是用的batchRemove方法来实现的,这里就不再讲一遍了

 

还有常用的截取的方法

public List<E> subList(int fromIndex, int toIndex)

java如何获取集合对象最大的值 java list 取最大值_java如何获取集合对象最大的值_39

这个是一个截取的方法,但是要注意下,这个截取后返回的是sublist类,并不是Arraylist类型。

阿里的手册里面有写道

java如何获取集合对象最大的值 java list 取最大值_迭代器_40

最后看一看这个forEach循环遍历

java如何获取集合对象最大的值 java list 取最大值_java_41

最终实现其实还是普通的for循环,只是要注意在使用的过程中不要对原list进行结构性改变,否则有可能会抛出异常。

最常用的这些方法我大致都列出了,欢迎大家来补充,有问题直接指出就行。互相学习!