JAVA Collection 源码分析(一)之ArrayList

  到今天为止,差不多已经工作一年了,一直在做的是javaweb开发,一直用的是ssh(sh)别人写好的框架,总感觉自己现在高不成低不就的,所以就像看看java的源码,顺便学习一下大牛的思想和架构,read and write一直是提高自己编程水平的不二法门,写博客只是记录自己的学习历程,方便回顾,写的不好的地方,请多多包含,不喜勿喷,好了废话少说,现在让我们开始我们的历程把,Let‘s go!!!!!!!!

  想看源码无从下手,不知道有没有跟我一样感觉的人们,今天用Intellij发现了可以找出类与类之间关系的图,可以让我们可以从上到下,各点击破。推荐给大家。

  由于图片太大,我只是截取了一部分图,主要是关于我今天所要分析的ArrayList的类图,从图中我们可以看到最顶层的是Collection接口,Collection接口定义了基本的一些方法,所定义的方法在AbstractCollection中得到了具体的实现,包括size()啊,toArray()....许多基本的方法,大家要是有兴趣的可以去看看源代码。下面我们进入ArrayList中进行具体的分析。

  直接上代码,我们从代码进行分析。

private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 数组初始的容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 其实ArrayList中维护的就是一个Object数组
     */
    private transient Object[] elementData;

    /**
     * 这个size指的不是数组的长度,而是数组中所存储的元素的个数,因为他所采用的是数组动态增长策略,下面我们会看到他的   * 具体策略的实现。
     *
     * @serial
     */
    private int size;

  接下来就是ArrayList的初始化,这个我就不贴源码了,public ArrayList(int initialCapacity)第一个初始化方法让你指定初始化容量的大小,public ArrayList(),

无参的初始化方法,他会默认将我们前面EMPTY_ELEMENTDATA = {}赋给elementData,这是我最常用的初始化方法,第三个初始化方法public ArrayList(Collection<? extends E> c)这是将一个实现了Collection接口的类的对象初始化,首先通过toArray方法将其转化成数组赋给elementData,我们直到elementData是一个Object数组,

所以它可以指向任何对象,接下来

if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);

这个很容易理解,如果当前的数组的Class不是Object,则将它转化为Object,按照我的理解就是重新开辟了空间然后让elementData指向它,不知道对不对,请清楚的可以指正我,我会进行修改的。好了,初始化分析完了,让我抽根烟整理整理思路先.....嘿嘿。

  

  我们接着看

  

/**
     * 确保数组容量的策略,首先将数组长度在增加两倍,     * 然后与Integer.MAX_VALUE - 8 进行比较,如果大于
     * 的话,则将数组长度増长至Integer.MAX_VALUE,否则就*/将其赋给Integer.MAX_VALUE-8,防止内存溢出
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != EMPTY_ELEMENTDATA)
            // any size if real element table
            ? 0
            // larger than default for empty table. It‘s already supposed to be
            // at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

  

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);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

  接下来就是常用的一些方法的具体算法实现了,我就不一一举例了,我在这挑上几个我感兴趣的说一说:

  

public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

  我们可以看到,在进行数组的操作的时候,大量的使用到了Arrays.copyOf工具方法,我为了一探究竟,跟踪了进去,看了一下源码,是最后发现其实是调用了一个叫做System.arraycopy的方法,在进去看到这个方法是一个native方法,有可能使用c或者c++写的,因为快吧,这是我的理解。

  

public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

  还有我们看到进行操作的时候大多数都有一个modCount++的操作,这是因为本身ArrayList不是线程安全的,所以在迭代的时候如果没有得到预期值的话,就会fast

fail.这个概念我有点模糊,决定去好好了解一下。

  在进行新增的时候都会进行数组容量的扩展,防止数组出现越界的错误,这也是我们可以从中学习到的一点。

  好了今天就先说这么多,其他的可以去看看源码,睡觉了。。。。。

JAVA Collection 源码分析(一)之ArrayList,布布扣,bubuko.com

时间: 2024-10-12 10:47:12

JAVA Collection 源码分析(一)之ArrayList的相关文章

JAVA Collection 源码分析(二)之SubList

昨天我们分析了ArrayList的源码,我们可以看到,在其中还有一个类,名为SubList,其继承了AbstractList. // AbstractList类型的引用,所有继承了AbstractList都可以传进来 private final AbstractList<E> parent; // 这个是其实就是parent的偏移量,从parent中的第几个元素开始的 private final int parentOffset; private final int offset; int s

Java Collection源码学习

Java集合类的顶层是Collection<E>接口, Collection接口是最基本的容器接口,继承至Iterable接口(主要通过其进行产生迭代器逐一的进行元素访问).其中的元素允许重复,可以无序. JDK没有提供直接实现Collection接口的实现类,它提供更具体的子接口如List.Set等. 继承自它的子接口包括BeanContext, BeanContextServices, BlockingDeque<E>, BlockingQueue<E>, Dequ

Java 集合源码分析(一)HashMap

目录 Java 集合源码分析(一)HashMap 1. 概要 2. JDK 7 的 HashMap 3. JDK 1.8 的 HashMap 4. Hashtable 5. JDK 1.7 的 ConcurrentHashMap 6. JDK 1.8 的 ConcurrentHashMap 7. 最后补充一下 HashMap 中的一些属性和方法 附:更这个系列感觉自己像是又挖了一个坑??,不过趁自己刚好工作不太忙,有空闲期,静下心来研究学习源码也是一件很值得做的事,自己尽量会把这个坑填完??.

超赞!推荐一个专注于Java后端源码分析的Github项目!

大家好,最近有小伙伴们建议我把源码分析文章及源码分析项目(带注释版)放到github上,这样小伙伴们就可以把带中文注释的源码项目下载到自己本地电脑,结合源码分析文章自己本地调试,总之对于学习开源项目源码会更方便. 因此下面提供[源码笔记]的Github地址,若您觉得不错,欢迎Star点亮哦: Github主页:https://github.com/yuanmabiji 源码分析文章:https://github.com/yuanmabiji/Java-SourceCode-Blogs Sprin

Java集合源码分析(二)ArrayList

ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类. ArrayList实现了Serializable接口,因此它支持序列化,能够通过

Java - LinkedList源码分析

java提高篇(二二)---LinkedList 一.概述 LinkedList与ArrayList一样实现List接口,只是ArrayList是List接口的大小可变数组的实现,LinkedList是List接口链表的实现.基于链表实现的方式使得LinkedList在插入和删除时更优于ArrayList,而随机访问则比ArrayList逊色些. LinkedList实现所有可选的列表操作,并允许所有的元素包括null. 除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾

Java集合源码分析(四)Vector&lt;E&gt;

Vector<E>简介 Vector也是基于数组实现的,是一个动态数组,其容量能自动增长. Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是相对安全,有些时候还是要加入同步语句来保证线程的安全),可以用于多线程环境. Vector没有丝线Serializable接口,因此它不支持序列化,实现了Cloneable接口,能被克隆,实现了RandomAccess接口,支持快速随机访问. Vector<E>源码 如下(已加入详细注释): /*

Java集合源码分析(三)LinkedList

LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全的,只在单线程下适合使用. LinkedList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了Cloneable接口,能被克隆. LinkedList源码 以下是linkedList源码(加入简单代码注释): /* * @(#)LinkedList.java 1.6

java 集合类源码分析--linkedlist

一.源码解析 1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clone()与toArray()9.遍历数据:Iterator()二.ListItr 一.源码解析 1. LinkedList类定义. public class LinkedList<E> extends AbstractSequentialList<E> implements List