java集合核心源码01——ArrayList

首先呢,对于ArrayList,相当于一个动态数组,里面可以存储重复数据,并且支持随机访问,不是线程安全的。对于更多的底层东西,且听分解。

打开源码,先看继承了哪些类,实现了哪些接口,然后继承的这些类或接口是否还有父类,一直深挖到顶部

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

可以看出,ArrayList集合继承了AbstractList类,实现了List,RandomAccess,Cloneable,Serializable这一系列接口,一个一个分析。

其中呢AbstractList类最终也是实现了Collection接口,List也是继承了Collection接口,同时呢Collection接口继承了Iterable接口。

对于Iterable接口呢,源码中解释说,for-each循环可以与任何实现了Iterable接口的对象一起工作,就是说该集合可以使用for-each循环。

对于Cloneable,Serializable这两个接口,代表该类支持克隆和序列化。

对于RandomAccess,实现了该接口,那么该类就支持快速的随机访问。LinkedList就没有实现该接口,需要用迭代器进行遍历。

对于AbstractList类,里面有一个属性modCount,这个属性主要是由集合的迭代器使用的,在迭代的过程中,会检查当前的List的modCount和自己保存的比较,是否发生了变化(变化是指该集合是否被其他线程并发修改),如果发生变化,就抛出java.util.ConcurrentModificationException异常,这种行为就是fail-fast机制

接下来,我们真正的走进ArrayList源码:

 transient Object[] elementData;

首先,ArrayList底层也是封装的一个数组,这个数组是被transient关键字修饰的,代表对象的临时数据,持久化对象时,不需要维持,所以不需要参与序列化,即用该关键字修饰。(该关键字修饰的实例变量不参与序列化)

然后呢,看一下ArrayList有哪些构造器:

  private static final int DEFAULT_CAPACITY = 10;//默认容量大小为10
  private int size;//提供私有变量保存数组的长度
  /**
  *接收一个int型的整数,初始化数组容量
  */
  public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     * 不接收任何参数,采用默认容量10
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 接收一个Collection类型的集合,把集合的元素复制到数组中
     *
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

另外呢讲一下ArrayList的扩容:

ensureCapacity()方法是用来首先计算出一个最小扩展的容量minExpand,然后所需要的最小容量和最小扩展容量相比较,如果大于,就会进入ensureExplicitCapacity方法,也是进行判断后,然后进入主要的方法grow方法,计算新的容量大小为旧容量+旧容量/2(右移一位相当于除以2)即为原来长度的1.5倍,为什么是1.5倍呢?因为由实验可得出,1.5倍不会浪费太大的内存。

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

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

public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

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

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        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 void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

从源码中可以看出,ArrayList没有实现任何的同步,所以不是线程安全的,其他的添加,删除方法可以自行点开源码查看,相应的很简单。

原文地址:https://www.cnblogs.com/javatalk/p/10123192.html

时间: 2024-11-10 22:02:54

java集合核心源码01——ArrayList的相关文章

Java HashMap 核心源码解读

本篇对HashMap实现的源码进行简单的分析. 所使用的HashMap源码的版本信息如下: /* * @(#)HashMap.java 1.73 07/03/13 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ 一.概述 在Java中每一个对象都有一个哈希码,这个值可以通过hashCo

5 手写Java Stack 核心源码

Stack是Java中常用的数据结构之一,Stack具有"后进先出(LIFO)"的性质. 只能在一端进行插入或者删除,即压栈与出栈 栈的实现比较简单,性质也简单.可以用一个数组来实现栈结构. 入栈的时候,只在数组尾部插入 出栈的时候,只在数组尾部删除** 我们来看一下Stack的用法 :如下 public static void main(String[] args){ //新建一个栈 Stack<String> stack = new Stack<>(); /

1 手写ArrayList核心源码

手写ArrayList核心源码 ArrayList是Java中常用的数据结构,不光有ArrayList,还有LinkedList,HashMap,LinkedHashMap,HashSet,Queue,PriorityQueue等等,我们将手写这些常用的数据结构的核心源码,用尽量少的代码来揭示核心原理. 下面我们来手写ArrayList的核心源码 首先我们定义一个QArrayList,不要问为什么叫QArrayList,因为我之前写过Qt,仅此而已.源码 public class<T> QAr

【java集合框架源码剖析系列】java源码剖析之TreeMap

注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于ArrayList的知识. 一TreeMap的定义: public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable 可以看到TreeMap是继承自AbstractMap同时实现了NavigableMap,

1小时手写SpringMVC T5大牛带你解读Spring核心源码(附详细视频教程)

SpringMVC简介 SpringMVC是当前最优秀的MVC框架,自从Spring 2.5版本发布后,由于支持注解配置,易用性有了大幅度的提高.Spring 3.0更加完善,实现了对Struts 2的超越.现在越来越多的开发团队选择了Spring MVC. Spring为展现层提供的基于MVC设计理念的优秀的Web框架,是目前最主流的MVC框架之一 Spring3.0后全面超越Struts2,成为最优秀的MVC框架 Spring MVC通过一套MVC注解,让POJO成为处理请求的控制器,而无须

Backbone事件机制核心源码(仅包含Events、Model模块)

一.应用场景 为了改善酷版139邮箱的代码结构,引入backbone的事件机制,按照MVC的分层思想搭建酷版云邮局的代码框架.力求在保持酷版轻量级的基础上提高代码的可维护性. 二.遗留问题 1.backbone的升级问题,新的特性无法引入 2.backbone中的潜在BUG,若官方已修复则无法同步更新 解决办法: 关注backbone官网的更新记录. http://github.com/documentcloud/backbone/ 三.核心源码 /** * @裁剪版backbone,仅包含Ev

Java集合框架源码阅读之AbstractCollection

AbstractCollection是集合实现类的根抽象实现类,它实现了Collection接口,集合中的三个分支Set.List.Queue都是继承此类之后再进行各自实现的扩展,分别是AbstractSet.AbstractList.AbstractQueue.这三个分支有一些共同之处,需要用一些共同的方法,因此出现了AbstractCollection类,它包含了一些这三个分支都会用到的常用方法.而这三个分支也各有抽象类,因为这三个分支下面的一些具体实现也会有一些当前分支通用的方法,因此也给

【Java】Java集合框架源码和数据结构简要分析——Set和Map

前言 之前一直把集合框架分成Collection和Map来对待,主要是基于储存内容是单列和双列,实际上这样来区分不太正确,set实际上是双列的结构. 现在回顾集合框架,看到很多当初看不到的东西. 现在来看集合框架,一部分是List,一部分是Set和Map,Set和Map几乎就是一回事. 本文假设你已经对集合框架有一定了解,关于细节请看<集合框架和Map基础>. 一.数据结构 不讲太深入的东西,实际上我也讲不了多深入. 数据结构,就是一堆数据的关系. 逻辑结构--数据逻辑上的关系,其实就是数据结

【Java】Java集合框架源码和数据结构简要分析——List

前言 之前一直把集合框架分成Collection和Map来对待,主要是基于储存内容是单列和双列,实际上这样来区分不太正确,set实际上是双列的结构. 现在回顾集合框架,看到很多当初看不到的东西. 现在来看集合框架,一部分是List,一部分是Set和Map,Set和Map几乎就是一回事. 一.数据结构 不讲太深入的东西,实际上我也讲不了多深入. 数据结构,就是一堆数据的关系. 逻辑结构--数据逻辑上的关系,其实就是数据结构,而数据的逻辑结构几乎可以分成四种:线性结构.集合结构.树形结构和图结构.