对Java ArrayList的自动扩容机制示例讲解

注意:

不同的JDK版本的扩容机制可能有差异

实验环境:JDK1.8

扩容机制:

当向ArrayList中添加元素的时候,ArrayList如果要满足新元素的存储超过ArrayList存储新元素前的存储能力,ArrayList会增强自身的存储能力,已达到存储新元素的要求

ArrayList:本质通过内部维护的数组对象进行数据存储

①:分析ArrayList的add(E)方法

 public boolean add(E e) {
  ensureCapacityInternal(size + 1); // Increments modCount!!
  elementData[size++] = e;
  return true;
 }

分析:add方法首先通过ensureCapacityInternal()方法确保当前ArrayList维护的数组具有存储新元素的能力,经过处理之后将元素存储在数组elementData的尾部

elementData:ArrayList真正用于存储元素的数组

②:分析ensureCapacityInternal方法

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

分析:ensureCapacityInternal判断ArrayList默认的元素存储数据是否为空,为空则设置最小要求的存储能力为必要存储的元素和默认存储元素个数的两个数据之间的最大值,然后调用ensureExplicitCapacity方法实现这种最低要求的存储能力

注意:ArrayList的存储空间并不是需要一个创建一个,而是分阶段性的创建,一般会预留存储空间。

例如,如果ArrayList需要存储10个元素,恰好ArrayList只能存储6个元素,剩余4个元素无法存储,ArrayList可能会一次性扩展10个元素,这种ArrayList就有20个元素的存储能力,在存储能力范围内,下次再存放元素,就不需要再次扩容

③:分析ensureExplicitCapacity方法:

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

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

分析:如果最低要求的存储能力>ArrayList已有的存储能力,这就表示ArrayList的存储能力不足,因此需要调用 grow();方法进行扩容

④:分析grow()方法

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

分析:当ArrayList扩容的时候,首先会设置新的存储能力为原来的1.5倍

 int newCapacity = oldCapacity + (oldCapacity >> 1);

如果扩容之后还是不能满足要求则MAX_ARRAY_SIZE比较,求取最大值,

如果MAX_ARRAY_SIZE大小的能力还是不能满足则通过hugeCapacity()方法获取ArrayList能允许的最大值:

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

从hugeCapacity方法看出,ArrayList最大的存储能力:存储元素的个数为整型的范围。

确定ArrayList扩容之后最新的可存储元素个数时,调用

elementData = Arrays.copyOf(elementData, newCapacity); 

实现elementData数组的扩容,整个流程就是ArrayList的自动扩容机制工作流程

扩展:

ArrayList的自动扩容机制底层借助于System实现

 public static native void arraycopy
 (Object src, int srcPos,
 Object dest, int destPos,
 int length);

arraycopy标识为native意味JDK的本地库,不可避免的会进行IO操作,如果频繁的对ArrayList进行扩容,毫不疑问会降低ArrayList的使用性能,因此当我们确定添加元素的个数的时候,我们可以事先知道并指定ArrayList的可存储元素的个数,这样当我们向ArrayList中加入元素的时候,就可以避免ArrayList的自动扩容,从而提高ArrayList的性能

ArrayList含参构造函数:初始化时指定存储元素的能力:

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

以上这篇对Java ArrayList的自动扩容机制示例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java ArrayList扩容问题实例详解

    本文研究的主要是Java ArrayList扩容问题实例详解的相关内容,具体介绍如下. 首先我们需要知道ArrayList里面的实质的其实是一个Object类型的数组,ArrayList的扩容问题其实就是这个Object类型的数组的扩容问题. transient Object[] elementData; 一.创建时,ArrayList的容量分配 创建一个ArrayList有三种情况 1.默认大小创建(默认为0) ArrayList al = new ArrayList(); 创建完成之后,al

  • Java中ArrayList在foreach里remove的问题详析

    前言 ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和IList接口 灵活的设置数组的大小 都说ArrayList在用foreach循环的时候,不能add元素,也不能remove元素,可能会抛异常,那我们就来分析一下它具体的实现.我目前的环境是Java8. 有下面一段代码: public class TestForEachList extends BaseTests { @Test

  • Java ArrayList.add 的实现方法

    ArrayList是平时相当常用的List实现, 其中boolean add(E e) 的实现比较直接: /** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boole

  • java 集合之实现类ArrayList和LinkedList的方法

    List 的方法列表 方法名 功能说明 ArrayList() 构造方法,用于创建一个空的数组列表 add(E e) 将指定的元素添加到此列表的尾部 get(int index) 返回此列表中指定位置上的元素 size() 返回此列表中的元素数 clear() 移除此列表中的所有元素 isEmpty() 如果此列表中没有元素,则返回true remove(int index) 移除此列表中指定位置上的元素 indextof(Object o) 返回此列表中首次出现的指定元素的索引,或如果此列表不

  • Java ArrayList add(int index, E element)和set(int index, E element)两个方法的说明

    一般使用List集合,估计都是使用这个ArrayList,一般呢也就是简单遍历数据和存储数据. 很少使用到add(int index, E element)和set(int index, E element)两个方法. 这两个方法,乍一看,就是在指定的位置插入一条数据. 区别: set()是更新,更新指定下标位置的值. add()是添加,区别于一般的add(E e),这个就是有个位置的概念,特殊位置之后的数据,依次往后移动就是了. 然后,看下面代码.来看看陷阱. 就算是,你知道了上面的内容,也不

  • java中申请不定长度数组ArrayList的方法

    如下所示: import java.util.ArrayList; //java中申请不定长度数组 public class Test01 { public static void main(String[] args) { // TODO Auto-generated method stub ArrayList list=new ArrayList(); list.add("123"); list.add("5"); list.add("5")

  • Java针对ArrayList自定义排序的2种实现方法

    本文实例讲述了Java针对ArrayList自定义排序的2种实现方法.分享给大家供大家参考,具体如下: Java中实现对list的自定义排序主要通过两种方式 1)让需要进行排序的对象的类实现Comparable接口,重写compareTo(T o)方法,在其中定义排序规则,那么就可以直接调用Collections.sort()来排序对象数组 public class Student implements Comparable{ private int id; private int age; p

  • Java中ArrayList的removeAll方法详解

    本文介绍的是关于Java中ArrayList的removeAll方法的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 在开发过程中,遇到一个情况,就是从所有骑手Id中过滤没有标签的骑手Id(直接查询没有标签的骑手不容易实现), List<Integer> allRiderIdList = new ArrayList(); // 所有的骑手,大致有23W数据 List<Integer> hasAnyTagRiderId = new ArrayList(); // 有标签

  • Java源码解析ArrayList及ConcurrentModificationException

    本文基于jdk1.8来分析ArrayList的源码 首先是主要的成员变量. /** * Default initial capacity. **/ private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. **/ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * Shar

  • Java中Arraylist动态扩容方法详解

    前言 本文主要给大家介绍了关于Java中Arraylist动态扩容的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. ArrayList 概述 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长.ArrayList不是线程安全的,只能用在单线程环境下.实现了Serializable接口,因此它支持序列化,能够通过序列化传输:实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问:实现了Cloneable接口,能被克隆.

随机推荐