当前位置: 首页 > news >正文

ArrayList无参构造添加元素源码解读

一、ArrayList无参构造add方法源码阅读

@Test//无参构造源码阅读
public void testArrayListNoConstructorAdd(){ArrayList<Integer> arrayList = new ArrayList<>();ArrayList<Integer> list = new ArrayList<>();arrayList.add(1);arrayList.add(12);arrayList.add(13);
}

就用这个为测试吧。

对于arrayList.add(1)debug进去:

看到进来了这里:

1、来到Integer类方法内部

public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}

对于IntegerCache.cache[i + (-IntegerCache.low)];这里应该是将cache索引为i - IntegerCache.low的元素返回,对于cache这个数组存储的个数是2x128 = 28

也就是可以存储[-128,127]这些元素。

不信可以借助工具查看:

在这里插入图片描述

发现确实是这样。

2、来到ArrayList的add方法:

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

size是什么?查看一下:

/*** The size of the ArrayList (the number of elements it contains).** @serial*/
private int size;

确实是大小,实锤了!!!

3、来到ensureCapacityInternal

private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//elementData是Object[0]@1098,不知道是什么,minCapacity是1
}

4、来到calculateCapacity:

private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//defaultcapacity_empty_elementdata这里是true的。return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY=10/**DEFAULT_CAPACITY: Default initial capacity.private static final int DEFAULT_CAPACITY = 10;*/}return minCapacity;
}

返回到:

ensureExplicitCapacity - > "Explicit是明确的意思"

来到:

private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);
}

minCapacity >elementData.length成立:

private void grow(int minCapacity) {// overflow-conscious codeint 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);
}

来到Arrays.copyof:

这里的original是一个对象吧

看到上一步是:

//类成员:transient Object[] elementData;

也就是elementData这个玩意,忍了很久了,之前一度怀疑这个是不是存储节点的数据,看看它的介绍发现果然是:

     * The array buffer into which the elements of the ArrayList are stored.* The capacity of the ArrayList is the length of this array buffer. Any* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* will be expanded to DEFAULT_CAPACITY when the first element is added.翻译下:* 存储 ArrayList 元素的数组缓冲区。* 数组列表的容量是此数组缓冲区的长度。任何* 空的数组列表与元素数据 == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* 将在添加第一个元素时扩展到 DEFAULT_CAPACITY。

那么就继续copyof这个方法:

public static <T> T[] copyOf(T[] original, int newLength) {return (T[]) copyOf(original, newLength, original.getClass());
}

首先,分析一下这个类,返回的是一个T泛型类,那么也就是和elementData同一个类型的对象。

来到:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {@SuppressWarnings("unchecked")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;
}

应该是走(Object)newType == (Object)Object[].class是true,于是走这边(T[]) new Object[newLength]了,然后再来到:

        System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));

这里很明显是将original的这里的内容拷贝到新的对象copy这个对象里了

,然后再返回新对象给:

public static <T> T[] copyOf(T[] original, int newLength) {

再回到:

private void grow(int minCapacity) {

返回copy给elementData.

再回到ArrayList的这个方法把里面的grow方法执行完再结束:

private void ensureExplicitCapacity(int minCapacity) {

结束。

再回到:

    private void ensureCapacityInternal(int minCapacity) {

再回到add方法将最后2行执行完就结束:

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

二、回顾:

第一步先去确认下容器大小怎么样。

如果是第一次add,就给10个容量。人哈就去扩容也就是grow方法。

这里的grow是怎么扩容呢?

看看源码:

private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)//如果比MAX_ARRAY_SIZE这个都大,那么就去newCapacity = hugeCapacity(minCapacity);//获取更大的容量// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}

这里就是先按照增加原来的一半容量吧。从int newCapacity = oldCapacity + (oldCapacity >> 1)可以看出。>>这个符号就是有符号右移嘛,也就是除以2。

总结一下:

对于无参构造创建的ArrayList,一开始容器大小也就是size = 0,当要添加元素时,便是第一次添加元素,会扩容10个大小。后面继续添加元素时每次都会和之前的容量大小比较一下,刚好不够了再扩容,扩大50%。

先做数据的迁移,再做数据的添加。

如果是第二次扩容1,那么就是添加第11个元素时,先去grow一下,新创建数组大小为15的copy(也就是扩容),然后迁移数据。然后再将copy返回给elementData,再进行add,将元素添加到已经扩容了的elementData的末尾,可以使用这个来查看一下:

@Test//无参构造源码阅读
public void testArrayListNoConstructorAdd(){ArrayList<Integer> arrayList = new ArrayList<>();ArrayList<Integer> list = new ArrayList<>();for (int i = 0; i <20; i++) {arrayList.add(i);}
}

过程和本文讲解的是一样的。

end

http://www.lryc.cn/news/45333.html

相关文章:

  • 手写简易 Spring(二)
  • 排列问题DFS入门
  • 【每日一题Day159】LC1638统计只差一个字符的子串数目 | 枚举
  • 【07 Metadata and VendorTag】
  • Golang中Model的使用
  • 交友项目【基础环境搭建】
  • 入职时,公司要求自己带电脑,每月给100元补贴,如果不接受就不能入职!
  • 20道经典Redis面试题
  • 十分钟带你看懂接口测试,2023最全超大型接口测试攻略
  • 【设计模式】创建型-单例模式
  • Python 练习 六
  • 「SQL面试题库」 No_22 员工奖金
  • 瞒不住了,Prefetch 就是一个大谎言
  • 这个时候了,你还不会不知道JavaMail API吧
  • JavaScript var let区别
  • Thinkphp 6.0容器和依赖注入
  • Type javax.servlet.http.HttpServletRequest not present
  • 一键配置Ubuntu的OpenHarmony基础编译环境
  • ASP网络求职招聘系统的设计与实现
  • 面试—C++《智能指针》常考点
  • 自动化测试方案编写思路
  • 【爬虫】案例04:某小说网多线程小说下载
  • 海外独立站创业,Shopify网站如何引流
  • 基于51单片机的室内湿度加湿温度声光报警智能自动控制装置设计
  • 解决:github爆 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
  • 【django开发手册】如何使用select_related进行一次连表查询
  • 二、MySQL 基础
  • 项目中常用写法(前端)
  • 【面试】Java并发编程面试题
  • HAProxy和Nginx搭建负载均衡器