ArrayList使用与分析

简介

java.util.ArrayList是Java集合框架中list接口的可变数组的实现,对list接口的全部实现以及允许null值,并提供相关可以操作底层存储数组的方法。

ArrayList底层的数据存储结构就是采用数组(数组是在内存中的一片连续的空间),也就是对ArrayList的操作就是对数组的操作,从而操作的时间复杂度和数组一样:

  • 访问特定元素:O(1)
  • 添加元素:O(1)
  • 插入/删除:O(n)
  • 搜索
    • 排序: O(logn)
    • 未排序:O(n)

使用

  • 创建一个ArrayList,3种方法:
// 使用无参构造函数
List<String> list = new ArrayList<>();

// 指定初始化大小
List<String> list = new ArrayList<>(16);

// 使用另外一个集合初始化
Collection<String> collection ...//某个集合
List<String> list = new ArrayList<>(collection);

其中,使用无参构造函数的创建方法默认初始化大小为10,源码如下:

/**
 * Default initial capacity.
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
  • 添加/插入
// new ArrayList
List<String> list = new ArrayList<>();

// 添加一个
list.add("A");

// 插入一个
// 注意指定位置大于数组大小,那么抛出`IndexOutOfBoundsException`异常
list.add(1,"B");

//  添加多个
list.addAll(Arrays.asList("C","D"));

// 插入多个
// 同样小心`IndexOutOfBoundsException`异常
list.addAll(1,Arrays.asList("E","F"));
  • 删除
List<String> list = ...// ArrayList

//移除特定元素
list.remove("A");

// 移除某个元素
list.remove(1);
  • 迭代/循环
//List<String> list = ...// ArrayList

// 使用`for-each`
for (String item : list) {
    //...
}

// 使用Iterator正向迭代
for(Iterator<String> i = list.iterator();i.hasNext();){
    String item = i.next();
    //...
}

// 使用ListIterator使用逆向迭代
for(ListIterator<String> i = list.listIterator(); i.hasPrevious();){
    String item = i.next();
    //...
}
  • 搜索
//List<String> list = ...// ArrayList

// 定位某个元素,一次出现,找不到返回-1
list.indexOf("A");
// 定位某个元素,最后一次出现,找不到返回-1
list.lastIndexOf("A");

// 查找多个,Java8 StreamAPI
List<String> result = list.stream().filter("D"::equals).collect(Collectors.toList());

// 如果对于排序的数据,可以通过二分搜索算法
List<String> copy = new ArrayList<>(stringsToSearch);
Collections.sort(copy);
int index = Collections.binarySearch(copy, "f");

源码分析&注意事项

添加时自动扩容
/**
 * 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 boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    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);
    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);
}

可以看出,添加时先判断最小容量是否允许添加,如果容量不够则通过grow扩容,扩大50%,通过oldCapacity>>1右移一位实现。其中,ArrayList最大为MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8)modCount用于保存扩容次数,用于迭代器的快速失败迭代。

Iterator 和 ListIterator

ListIterator是Iterator子类,相对于Iterator,新增了逆序迭代添加替换等功能。

image.png
使用注意
  • 在添加大量元素前,应用程序可以使用ensureCapacity 操作来增加ArrayList实例的容量或者在初始化的时候执行需要使用的大小,这可以减少递增式再分配的数量。
  • 非线程安全,同步使用的时候需要外部同步锁,简单的可以通过包装实现:
    List list = Collections.synchronizedList(new ArrayList(...)); 
    

参考:

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

推荐阅读更多精彩内容