当我们在聊ArrayList

本文出自:https://blog.csdn.net/DT235201314/article/details/79867960

一丶概述

面试:说说HashMap的底层实现原理?

小明:Android开发平时用ArrayList就够了,很少用HashMap。

面试:那你说说ArrayList

小明:。。。。

面试都喜欢问HashMap底层原理,而ArrayList是最长用到的,先说说ArrayList

二丶源码与原理

1.初始化

/**
 * ArrayList初始化默认容量大小为10,见无参构造函数。
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * 空实例共享的空数组实例。
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * ArrayList成员存储在这个数组缓冲区中。
 * 容量大小是这个缓冲区的长度
 * 在添加第一个成员时都会扩充到DEFAULT_CAPACITY大小,即容量为10。
 * transient这个关键字告诉我们该对象在序列化的时候请忽略这个元素
 */
transient Object[] elementData;

/**
 * 逻辑长度
 */
private int size;

/**
 * 传入长度
 */
public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = new Object[initialCapacity];
}

/**
 * 初始化长度为10的数组
 */
public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;
}

/**
 *创建一个包含collection的ArrayList
 */
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}
image.png

说名:1:ArrayList底层是Object[]数组;2.空ArrayList指向同一个空数组,3.默认长度为10;

2.add方法:当ArrayList加入对象呢?

/**返回永远为true 无限扩容*/
public boolean add(E e) {
    // 确定ArrayList的容量大小
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //添加e到ArrayList中
    elementData[size++] = e;
    return true;
}
/**指定位置添加元素*/
public void add(int index, E element) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}
/**添加一个元素*/
public void add(E e) {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();

    try {
        int i = cursor;
        ArrayList.this.add(i, e);
        cursor = i + 1;
        lastRet = -1;
        expectedModCount = modCount;
        limit++;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}
/**确定ArrarList的容量*/
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == 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);
}

3.ArrayList扩容原理

/**扩容1.5倍,并重新copy值*/
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    // 若ArrayList的容量不足以容纳当前的全部元素则*1.5,设置 新的容量=“oldCapacity + (oldCapacity >> 1)
    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倍,就对啦):

image.png
image.png

4.Arrays.copyof()和System.arraycopy()方法

Arrays.copyof()

public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

System.arraycopy()

/**
 *native修饰为用其它语言(C/C++)实现方法
 * @param src  要拷贝的数组
 * @param srcPos 要拷贝数组起始位置
 * @param dest 目标数组
 * @param destPos 目标数组要拷贝的起始位置
 * @param length 要拷贝长度
 */
public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

5.其他方法(略)

fill :填充元素

remove:删除元素,后面元素会前移

fastremove:截取后部分

......

6.特点

image.png

7.时间复杂度

底层数组存/取元素效率非常的高(get/set),时间复杂度是O(1),而查找,插入和删除元素效率似乎不太高,时间复杂度为O(n)。

三丶推荐文章:

ArrayList初始化 - Java那些事儿

ArrayList底层数组扩容原理 - Java那些事儿专栏

时间复杂度 - Java那些事儿专栏

三顾ArrayList

ArrayList的时间复杂度 - Java那些事儿专栏

迄今为止看过最好的系列文章

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

推荐阅读更多精彩内容

  • ArrayList 源码分析 不知道各位朋友,还记得开工前制定的学习目标么? 有没有一直为了那个目标废寝忘食呢?继...
    醒着的码者阅读 1,328评论 5 11
  • 在一个方法内部定义的变量都存储在栈中,当这个函数运行结束后,其对应的栈就会被回收,此时,在其方法体中定义的变量将不...
    Y了个J阅读 4,390评论 1 14
  • ArrayList 详解 底层是数组,查询快增删慢,线程不安全,效率高。初始化长度10 说一下ArrayList底...
    奇点一氪阅读 365评论 0 0
  • 常怀感恩之心,人似乎都变得温和了。 变得不想不会去计较太多,会不自觉的去感谢和感恩遇到的每一件事,每一个人。 很是...
    夏励阅读 179评论 0 1
  • 因为工作的原因,我在公司负责自酿葡萄酒带活动。昨晚和两个年轻同事喝红酒,他们觉得有个宿舍红酒小吧也可以,喝一杯放松...
    枫林上学阅读 349评论 0 0