ArrayList<E>源码分析

ArrayList是按照线性表结构实现的

ArrayList的主要继承结构

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

public interface List<E> extends Collection<E>

public interface Collection<E> extends Iterable<E>

public interface Iterable<T>

1.属性

    private static final long serialVersionUID = 8683452581122892189L;//序列化ID

    private static final int DEFAULT_CAPACITY = 10;//默认初始化数组的长度是10

    private static final Object[] EMPTY_ELEMENTDATA = {};//空数组,在构造时,如果参数是0,就用它

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//空数组,在构造时,如果没有参数,就用它

    transient Object[] elementData; //arrayList存放数据的数组

    //将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

    private int size; //arrayList的长度 默认是0

2.构造器

提供了3个构造器

//指定数组默认初始化的长度//如果大于0,就创建一个指定长度的数组//如果等于0,就默认是一个空数组 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);
        }
    }

//如果不指定任何参数,就默认是一个空数组
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
//把其他的Collection对象放到它这里,如果长度是0,就指定一个空数组;否则把传入对象的所有数据一一拷贝到新数组里
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

3.添加数据

动态扩容策略

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  //先给数组扩容,如果空间够用,就不用扩;否则按照一定的策略进行扩容
        elementData[size++] = e;
        return true;
    }

 private void ensureCapacityInternal(int minCapacity) {

    //如果当前的数组是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,就初始化数组的长度 = MAX(10 , size+1)
    //使用数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA时,说明使用的是没有参数的构造器
       if (elementData == DEFAULTCAPACITY_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);//数组扩容策略:增加原数组长度左移位(oldCapacity >> 1)
        if (newCapacity - minCapacity < 0)//如果新增的数组长度还是小于数据的个数,就把新数组的长度(newCapacity)等于数据的个数(minCapacity)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)//如果新数组的长度大于最大数组长度说明数组的长度也忒大了,就启动超级扩容策略hugeCapacity()        newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);//最后按照newCapacity的长度,把原先的数据拷贝到新数组
    }
 private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE : //2147483647
            MAX_ARRAY_SIZE; //2147483639

    //数组的最大长度就是Integer.MAX_VALUE(2147483647)
    }

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

/****************************************************************/

Arrays.class:

    public static int[] copyOf(int[] original, int newLength) {
      int[] copy = new int[newLength];
      System.arraycopy(original, 0, copy, 0,
      Math.min(original.length, newLength));
      return copy;
    }

 

4.整理数组

//如果当前数组的长度大于数据存放的长度,那么就把当前数组换成新数组( 按照数据存放的长度重新创建的数组,然后把数据放到新数组里 )//这样能有效节省数组空间 public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }
时间: 2024-10-06 19:44:19

ArrayList<E>源码分析的相关文章

ArrayList部分源码分析(基于1.8)

今天分析第一个集合类:ArrayList 首先,说一下我读这部分源码的感受. ArrayList类底层实现实际上是数组,因此很多操作会调用很多本地(Native)方法来实现或者部分实现.用java实现的很多方法中,只是用java代码进行了一些必要的逻辑判断和变量值的改变. 在AbstractList中加入的modCount变量是为了配合迭代器的使用. 下面是部分源码分析: package java.util; import java.util.function.Consumer; import

Java——ArrayList底层源码分析

1.简介 ArrayList 是最常用的 List 实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔, 当数组大小不满足时需要增加存储能力,就要将已经有数组的数据复制到新的存储空间中. 当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进行复制.移动.代价比较高.因此,它适合随机查找和遍历,不适合插入和删除. 线性表的顺序存储,插入删除元素的时间复杂度为O(n),求表长以及增加元素,取第 i 元素的时间复杂度为O(1). ArrayL

ArrayList的源码分析(基于jdk1.8)

1.初始化 transient Object[] elementData; //实际存储元素的数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList() { //初始化为一个默认的空数组 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 2. 添加元素 private static final int DEFAU

ArrayList的源码分析

/** Default initial capacity. 初始化容量为10 */private static final int DEFAULT_CAPACITY = 10;private static final Object[] EMPTY_ELEMENTDATA = {};/** Shared empty array instance used for default sized empty instances. We distinguish this from EMPTY_ELEMEN

Vector和Stack源码分析/List集合的总结

序言 这篇文章算是在这list接口下的集合的最后一篇了,前面ArrayList.LinkedList都已经讲解完了,剩下就Vector和Vector的子类Stack啦.继续努力.一步一个脚印, --WH 扩展 学习vector,需要一些多线程的知识,这里比较杂,主要讲解一下等会会用到的 1.锁机制:对象锁.方法锁.类锁 对象锁就是方法锁:就是在一个类中的方法上加上synchronized关键字,这就是给这个方法加锁了. 类锁:锁的是整个类,当有多个线程来声明这个类的对象的时候将会被阻塞,直到拥有

Java集合源码分析之LinkedList

1. LinkedList简介 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable 可以看到LinkedList类继承AbstractSequentialList类,实现了List, Deque, Cloneable, java.io.Serializable接口.实

2、JDK8中的HashMap实现原理及源码分析

本篇提纲.png 本篇所述源码基于JDK1.8.0_121 在写上一篇线性表的文章的时候,笔者看的是Android源码中support24中的Java代码,当时发现这个ArrayList和LinkedList的源码和Java官方的没有什么区别,然而在阅读HashMap源码的时候,却发现Android中的Java与官方版的出入略大,遂不得不转而用Eclipse导入jdk源码阅读,这里不得不吐槽一句,用惯了IDEA的快捷键,Eclispe还真是用不习惯~~好了,接下来我们言归正传: 一.什么是Has

JAVA Collection 源码分析(一)之ArrayList

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

Java中ArrayList源码分析

一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保证容量能容纳所有数据. 1.1.ArrayList 的继承与实现接口 ArrayList继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口. public class  ArrayList<E> ex