Java ArrayList扩容实现原理

一、.ArrayList:

写过的项目到现在基本上面向业务域查询返回大列表都是使用ArrayList来存储业务数据的。

定义:ArrayList是List接口的可变数组的实现。实现了所有的可选列表的操作并允许包括null在内的所有元素。除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。

每个ArrayList实例都有一个容量,该容量是指来存储列表元素的数组的大小,该容量至少等于列表数组的大小,随着ArrayList的不断添加元素,其容量也在自动增长,自动增长会将原来数组的元素向新的数组进行copy。因此,如果根据业务场景来提前预判数据量的大小。可在构造ArrayList时指定其容量。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加ArrayList实例的容量,这样就可以减少递增式再分配数量的操作。

注意:我们都知道ArrayList不是线程安全的,如果存在多线程访问ArrayList实例的场景,其中一个线程要在改变ArrayList列表结构之前,需要先对它这个操作保持线程同步。

ArrayList继承了AbstractList抽象类并实现了List接口,底层使用数组保存所有元素。


AbstractList主要作用是定义抽象对数组操作的公共主要行为,供具备相似功能的子类来具体实现自己特定的逻辑。

二、初始化

public ArrayList();默认的构造器,将会以默认的大小来初始化内部的数组

public ArrayList(int initialCapacity);用指定的大小来初始化内部的数组

public ArrayList(Collectio<? extends E> c);用一个ICollection对象来构造,并将该集合的元素添加到ArrayList


public ArrayList();默认的构造器

/**

* Shared empty array instance used for empty instances.

*/

private static final Object[] EMPTY_ELEMENTDATA = {};

/**

* Constructs an empty list with an initial capacity of ten.

*/

public ArrayList() {

super();

this.elementData = EMPTY_ELEMENTDATA;

}

我本地JDK1.7 默认数组长度是0,JDK1.6初始化大小是10

(1)添加元素,确定内部容量

/**

* Default initial capacity.

*/

private static final int DEFAULT_CAPACITY = 10;

/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @returntrue(as specified by {@link Collection#add}) */ 

 public boolean add(E e) { 

 ensureCapacityInternal(size + 1); //确保内部容量,判断当前容量大小,如果不够就通过扩容来确保容量;size大小表示执行添加元素之前的元素个数,并不是ArrayList的容量,容量是elementData数组长度

 // Increments modCount!! 

 elementData[size++] = e; 

 return true;

 }

下面关注下ensureCapacityInternal(size + 1)是如何扩容的。

private void ensureCapacityInternal(int minCapacity) {

//如果实际存储数组是空数组,则最小的容量是默认容量,JDK1.7是10

if (elementData == EMPTY_ELEMENTDATA) {

minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

}

ensureExplicitCapacity(minCapacity);

}

private void ensureExplicitCapacity(int minCapacity) {

modCount++;

// overflow-conscious code

//如果数组长度elementData.length小于最小容量就需要扩容

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}

以上,elementData是用来存储实际数据的数组,minCapacity是最小的扩容容量。

三.扩容(重点)

/**

* 增加容量,以确保它至少能容纳由最小容量参数指定的元素数

* @param minCapacity 所需要的最小容量

*/

private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

// int newCapacity = oldCapacity + oldCapacity * 0.5 也就是扩容了1.5倍

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

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

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

// 这个最大值用来分配给数组的,由于不同的JVM需要在数组中需要存放些头部信息,如果分配过大可能会导致内存溢出:提示请求的数组大小超过了JVM限制

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;

}

总结:ArrayList是采取延迟分配对象数组大小空间的,当第一次添加元素时才会分配10个对象空间,当添加第11个元素的时候,会扩容1.5倍,当添加到16个元素的时候扩容为15*1.5=22,以此类推。

ArrayList每次扩容都是通过Arrays.copyof(elementData, newCapacity)来实现的。

当我们在明确对象的大致数目时候提前指定初始化数组的大小是一个非常明智的选择。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 文章有点长,比较啰嗦,请耐心看完!(基于Android API 25) 一、概述 首先得明白ArrayList在数...
    JerryloveEmily阅读 3,189评论 2 15
  • 【默默耕耘】20161206 day 13 Tuesday 1.画日记:听了一遍第三节课。回家 洗手时就和儿子商量...
    ysmalina阅读 170评论 0 0
  • 明天要出趟远门,心里乱糟糟的,我不是个特别胆儿大的人,也不常一个人睡,所以啊,真是有些忧心。还要去学校办事,...
    小镇Y胖Y阅读 184评论 0 0
  • 粽子节后…… 回首和妳…… 我……和……我来时的路…… 都已成了风景…… TMD…… 有个人…… 住在心底…… 却...
    晔0114阅读 101评论 0 2
  • 总有一天会无可自拔的爱上自己啊,虽然目前对于各方面还是诸多挑剔。最近做梦老梦见以前都不曾过多关注的老同学,一群群的...
    阿琳家的阿佳和阿飞阅读 158评论 0 1