ArrayList的源码分析(基于jdk1.8)

1.初始化

transient Object[] elementData;  //实际存储元素的数组

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList() {
    //初始化为一个默认的空数组
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

2. 添加元素

private static final int DEFAULT_CAPACITY = 10;//默认容量

public boolean add(E e) {
    //确保当前数组的容量是够得
    ensureCapacityInternal(size + 1);  // Increments modCount!!

    //将新元素添加到[size++]的位置
    elementData[size++] = e;
    return true;
}
private void ensureCapacityInternal(int minCapacity) {
    //如果是第一次添加
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      //扩容为默认容量大小:10
      minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    //每一次添加都要判断是否需要扩容
    ensureExplicitCapacity(minCapacity);
}

3.扩容

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

    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);

    // 拷贝原数组中的元素至新数组,并返回新数组的引用
    elementData = Arrays.copyOf(elementData, newCapacity);
}

4.结论

  ArrayList物理结构是数组,决定了它的存储特点是:需要开辟连续的存储空间来存储元素,当存储容量不够时,需要扩容,增加容量为原来的1.5倍。类似的,Vector的物理结构也是数组,当存储容量不够时,需要扩容为原来的2倍。那么是1.5倍好呢?还是2倍好呢?1.5倍使得数组空间使用率提高了,但是这也增加了扩容的频率。所以,建议大家在选择动态数组时,如果对要存储的元素个数有一个预估时,那么可以在创建ArrayList时,就使用ArrayList(int initialCapacity) 构造器,避免反复扩容。

原文地址:https://www.cnblogs.com/duoduotouhenying/p/10136406.html

时间: 2024-10-09 23:17:14

ArrayList的源码分析(基于jdk1.8)的相关文章

ArrayList源码分析(基于JDK1.8)

ArrayList底层是一个Object类型数组 .对数组的所有增删改查操作都是基于数组的. ArrayList的属性 //默认初始化容量是10 private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; //ArrayList默认初始化大小 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEM

HashMap源码分析-基于JDK1.8

以下内容翻译于HashMap类的注释 HashMap是map接口的基础实现类.这个实现提供了所有可选的Map接口操作.并且允许null键和null值.HashMap类和Hashtable类差不多,只是HashMap不是线程完全的,并且HashMap允许null值和null键.这个类不保证map元素的顺序,也不保证顺序会随着时间保持不变. 假如hash函数能够使元素在桶中(buckets)均匀地分散,HashMap对于基本的get,put操作提供稳定的性能.集合视图的遍历需要的时间和HashMap

AtomicInteger源码分析——基于CAS的乐观锁实现

AtomicInteger源码分析--基于CAS的乐观锁实现 1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及到清空寄存器,缓存数据.然后重新加载新的thread所需数据.当一个线程被挂起时,加入到阻塞队列,在一定的时间或条件下,在通过notify(),notifyAll()唤醒回来.在某个资源不可用的时候,就将cpu让出,把当前等待线程切换为阻

Spark资源调度机制源码分析--基于spreadOutApps及非spreadOutApps两种资源调度算法

Spark资源调度机制源码分析--基于spreadOutApps及非spreadOutApps两种资源调度算法 1.spreadOutApp尽量平均分配到每个executor上: 2.非spreadOutApp尽量在使用单个executor的资源. 源码分析 org.apache.spark.deploy.master.Master 1.首先判断,master状态不是ALIVE的话,直接返回2.调度driver3. Application的调度机制(核心之核心,重中之重) 源码如下: 1 /*

Spring IoC 源码分析 (基于注解) 之 包扫描

在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫描的过滤规则.那我们今天就来看下包扫描的具体过程. 还是先看下面的代码: AnnotationConfigApplicationContext类 //该构造函数会自动扫描以给定的包及其子包下的所有类,并自动识别所有的Spring Bean,将其注册到容器中 public AnnotationConf

ArrayList部分源码分析(基于1.8)

今天分析第一个集合类:ArrayList 首先,说一下我读这部分源码的感受. ArrayList类底层实现实际上是数组,因此很多操作会调用很多本地(Native)方法来实现或者部分实现.用java实现的很多方法中,只是用java代码进行了一些必要的逻辑判断和变量值的改变. 在AbstractList中加入的modCount变量是为了配合迭代器的使用. 下面是部分源码分析: package java.util; import java.util.function.Consumer; import

epoll源码分析(基于linux-5.1.4)

API epoll提供给用户进程的接口有如下四个,本文基于linux-5.1.4源码详细分析每个API具体做了啥工作,通过UML时序图理清内核内部的函数调用关系. int epoll_create1(int size): 创建一个epfd句柄,size为0时等价于int epoll_create(0). int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event): 向epfd上添加/修改/删除fd. int epoll_w

HashMap 源码分析 基于1.8

1.个人总结及想法: (1)1.8相比较于1.7的变化? HashMap的底层数据结构大家应该都比较清楚了,就是数组+链表,链表主要用来解决hash冲突,使用了链地址法的方式来解决,1.8的改动主要就是hash冲突时候,一是在进行链表插入时由1.7的头插法变成了尾插法,第二个原来链表是一个单链表,但是现在超过红黑树的阀值过后就会自动升级为红黑树,阀值是链表节点超过8个节点(建立在数组已经扩容到64,否则优先选择扩容来解决冲突).当链表节点少于6个时红黑树会退化成普通链表. (2)1.8会出现1.

面试(1)-HashMap原理与源码分析(JDK1.8)

1.HashMap介绍 HashMap为Map接口的一个实现类,实现了Map所有的操作.HashMap除了允许key.value为null值和非线程安全外,其他实现几乎和HashTable一致.HashMap使用散列存储的方式保存kay-value键值对,因此其不支持数据保存的顺序.如果想要使用有序容器可以使用LinkedHashMap.在性能上当HashMap中保存的key的哈希算法能够均匀的分布在每个bucket中的时候,HashMap在基本的get和set操作的的时间复杂度都是O(n).在