1、ArrayList源码解析(arrays.aslist()的源码)

  本篇文章为你整理了1、ArrayList源码解析(arrays.aslist()的源码)的详细内容,包含有arraylist 源码 arrays.aslist()的源码 array.sort源码 arrays.sort()源码 1、ArrayList源码解析,希望能帮助你了解 1、ArrayList源码解析。

  目录1 概述2 底层数据结构3 构造函数4 自动扩容5 set() get() remove()6 Fail-Fast机制

  ArrayList的元素:有序、可重复、允许null

  ArrayList没有实现同步(synchronized),因此线程不安全的。(vector线程安全)

  ArrayList底层数据结构为数组,容量(capacity):表示底层数组长度。容量不足则触发扩容,创建一个更长的数组,并将元素迁移到新数组

  关于数组:数组一旦被创建,长度不可变

  2 底层数据结构

  几个重要的成员变量

  

 transient Object[] elementData; //存储列表元素的数组,容量(capacity)就是elementData的长度

 

   private int size;//元素的数量

   protected transient int modCount = 0; //list的修改次数

   private static final int DEFAULT_CAPACITY = 10; //初始化没有指定容量时,容量达到10就会触发扩容

  

 

  ps:size跟capacity不一样,capacity =size

  3 构造函数

  三个构造函数

  指定初始容量大小,创建Object类型数组,且长度等于参数值

  未指定初始容量大小,数据数组赋值为一个无限容量的空数组

  造参数为集合类型,将参数转换成Object类型数组,并赋值给数据数组

  注意,只有当第一次add元素时,才会指定数组的长度

  源码:

  

 // 1、指定初始容量大小时,创建Object类型数组,且长度等于参数值

 

   public ArrayList(int initialCapacity) {

   if (initialCapacity 0) {

   this.elementData = new Object[initialCapacity];

   } else if (initialCapacity == 0) {

   this.elementData = EMPTY_ELEMENTDATA; //参数值为0,数据数组赋值为一个无限容量的空数组

   } else {

   throw new IllegalArgumentException("Illegal Capacity: "+

   initialCapacity);

  // 2 不指定初始容量大小时,数据数组赋值为一个无限容量的空数组

   public ArrayList() {

   this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

  // 3 构造参数为集合类型,将参数转换成Object类型数组,并赋值给数据数组

   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;

  

 

  4 自动扩容

  添加元素时,会判断添加后是否超出当前数组长度,超出则会执行数组扩容;

  数组扩容时,会将老数组中的元素拷贝到新数组。

  如果未指定初始容量,那么容量达到10就会触发扩容

  数组扩容后的容量为原来的1.5倍

  尽可能评估所需要容量的大小,避免扩容。(因为扩容占用更多的内存)

  参考源码:

  重点!!!!!:添加前,都判断是否需要扩容:(如果size+1后,超过elementData的长度,则执行扩容,扩容为原来的1.5倍)

  

 

 

  public boolean add(E e) {

   ensureCapacityInternal(size + 1); // size 初始值为0,

   elementData[size++] = e;

   return true;

  private void ensureCapacityInternal(int minCapacity) {

   ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

  //计算所需容量:初始化未指定容量,第一次添加元素时,扩容阈值为10;反则,容量为当前长度+1

  private static int calculateCapacity(Object[] elementData, int minCapacity) {

   if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

   return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY = 10,即第一次添加时,数组长度变为10

   return minCapacity;//如果数组不为空时,最小长度是当前长度+1

  //再次计算数组所需容量

  private void ensureExplicitCapacity(int minCapacity) {

   modCount++;//列表修改次数递增

   //所需容量大于数组的长度,则执行扩容

   if (minCapacity - elementData.length 0)

   grow(minCapacity);

  //扩容,数组的内存状态已经发生变化了

  private void grow(int minCapacity) {

   int oldCapacity = elementData.length;

   int newCapacity = oldCapacity + (oldCapacity 1);// 新的长度为旧长度的1.5倍 【右移1位(除以2)】

   if (newCapacity - minCapacity 0) // 如果扩容后的长度小于所需要的最小长度,则使用最小长度(基本不会发生)

   newCapacity = minCapacity;

   if (newCapacity - MAX_ARRAY_SIZE 0) //这里是极限的情况,即逼近数组分配的最大内存空间

   newCapacity = hugeCapacity(minCapacity);

   elementData = Arrays.copyOf(elementData, newCapacity); // 执行数组拷贝

  

 

  5 set() get() remove()

  set()方法也就变得非常简单,直接对数组的指定位置赋值即可。

  

public E set(int index, E element) {

 

   rangeCheck(index);//下标越界检查

   E oldValue = elementData(index);

   elementData[index] = element;//赋值到指定位置,复制的仅仅是引用

   return oldValue;//返回原先位置上的元素

  

 

  get()方法同样很简单,唯一要注意的是由于底层数组是Object[],得到元素后需要进行类型转换。

  

public E get(int index) {

 

   rangeCheck(index);

   return (E) elementData[index];//注意类型转换

  

 

  remove()方法也有两个版本,一个是remove(int index)删除指定位置的元素,另一个是remove(Object o)删除第一个满足o.equals(elementData[index])的元素。删除操作是add()操作的逆过程,需要将删除点之后的元素向前移动一个位置。需要注意的是为了让GC起作用,必须显式的为最后一个位置赋null值。

  

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; //清除该位置的引用,让GC起作用

   return oldValue;

  

 

  6 Fail-Fast机制

  ArrayList也采用了快速失败的机制,通过记录 modCount 参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

  以上就是1、ArrayList源码解析(arrays.aslist()的源码)的详细内容,想要了解更多 1、ArrayList源码解析的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: