java-List集合的源码分析(数据结构方面,源码注释方面),迭代器快速失败机制

List实现了Collection接口,产生三个子类:ArrayList,LinkedList,Vector

文章包含解释方面:
数据结构方面,
源码注释方面&迭代器快速失败机制

方面1—基于源码的数据结构

基于源码的数据结构,我们先给出如下比较结果:

ArrayList&Vector是基于数组的实现。
那么他们:

-基于数组下标的快速查找功能

-数据插入费力,因为要移动一大段数据为新数据提供插入位

-数组可能溢出(已经被开发者利用grow()扩容解决)

必须是一片连续内存空间

注解:
我们看一下ArrayList的扩容源码(Vector省略(扩容一倍)):
判断是否扩容代码,在发生在每次添加数据时(每次使用size+数据长度和当前容量比较),但是源码里面规定了当数组容量小于10(DEFAULT_CAPACITY )时不会进行扩容
ArrayList:

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

我们发现扩容很简单,但是也是耗费系统资源的,协调用法比较重要

int newCapacity = oldCapacity + (oldCapacity >> 1);
elementData = Arrays.copyOf(elementData, newCapacity);

这两句说,
当发生扩容时先对原有的数组长度进行右移一位,也就是扩容一半(减少扩容次数,增大用量 )

LinkedList基于双向链表的实现。
那么:

-读取数据效率低一些,因为是双向链表,每次查询都得从头|尾进行遍历节点

-插入效率高些,不管前中后,插入都快,因为他不需要移动大量数据

-当数据过多时,节点(Node对象)本身也是一种资源消耗,数组实现不会

-是一个不连续内存空间

我们看出前者适合多查询,少插入的数据,后者适合多插入,少查询的数据

不过一般大家都是综合考虑。

方面2—基于各个源码的类的主要注释

基于各个源码的类的注释
给出LinkedList:
java-List集合的源码分析(数据结构方面,源码注释方面),迭代器快速失败机制_第1张图片
阅读发现,LinkedList是线程不安全的,它的迭代器是快速失败的
他允节点为null值,遍历都是从头或尾开始的

ArrayList:
java-List集合的源码分析(数据结构方面,源码注释方面),迭代器快速失败机制_第2张图片
阅读发现,ArrayList是线程不安全的,它的迭代器是快速失败的
它是大小可变的,复杂度为O(n)
Vector:
java-List集合的源码分析(数据结构方面,源码注释方面),迭代器快速失败机制_第3张图片
阅读发现,Vector是线程安全的(那消耗资源也会多),迭代器也是快速失败的。

**对于ArrayList,LinkedList的线程不安全,可在创建时利用Collections.synchronizedList进行"包装"
即:

List list=Collections.synchronizedList(new LinkedList());

关于迭代器的快速失败(异常访问操作,必须抛异常)

在此时,我们三个类一起看,发现他们的类,迭代器都是快速失败的,
什么是快速失败?
这是一种集合的错误处理机制(Map,Set也有),他会尽全力抛出ConcurrentModificationException异常(因为判断抛出的标准是值是否相等,而开发者并不保证值被人为修改),在你通过自身迭代器遍历时,对集合内容修改的时候,就会直接抛异常,退出迭代

其实原因很简单,源码里面有个modCount变量,他会在集合迭代时,每次增删时加一(其他非迭代修改没问题),迭代器会通过这个变量是否改变( modCount!=expectedmodCount)进行决定抛异常(在每次迭代下一个元素时next()会触发
这是一种判断方式,这样会保护集合的正确性,也既是保证集合不能并发访问。

如果还是不对,可以百度:

java中的fail-fast(快速失败)机制

这样再一看List发现再也不是只知形不知意了。

ps:源码学习目前只能靠边看代码边写博客进行总结,没什么更多的有效方法,朋友们可以的话,留下你宝贵的学习 建议|方法,我一定虚心接受。

你可能感兴趣的:(技术性,java,java-jdk源码学习)