行业资讯 2025年06月7日
0 收藏 0 点赞 311 浏览 4083 个字
摘要 :

在进行ArrayList学习过程中,看到了很多人说ArrayList在无参构造时会创建一个默认容量为10的数组,但是当我查看了ArrayList的源码,却发现其无参构造时,明明指向的是一……

在进行ArrayList学习过程中,看到了很多人说ArrayList在无参构造时会创建一个默认容量为10的数组,但是当我查看了ArrayList的源码,却发现其无参构造时,明明指向的是一个空数组:

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

  /**

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

     */

    public ArrayList() {

        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

    }

1

2

3

4

5

6

7

但是,仔细看一下这个无参构造函数的注释,确实是说构造一个初始容量为10的空列表,似乎有点自行矛盾呢,别急,我们再看一下DEFAULTCAPACITY_EMPTY_ELEMENTDATA的注释,你会发现它的注释存在这样的一句话,++***We distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when first element is added.***++ 这里的核心信息是当第一次进行add操作添加元素时,可以知道容量的扩容值;

再看一下elementData的源码注释,也有这样一句话: ++***Any empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA will be expanded to DEFAULT_CAPACITY when the first element is added.***++ 意思是: 添加第一个元素时,任何带有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空ArrayList都将扩展为DEFAULT_CAPACITY(10);

初步猜测,所有的new ArrayList<>()进行无参构造之后,指向的都是堆内存中的统一的一个地址,也就是静态存储区中DEFAULTCAPACITY_EMPTY_ELEMENTDATA所指向的那个空数组的位置,只有在进行第一次add操作之后,才会构造一个容量为10的数组。

我接着查看了ArrayList的add()方法源码,对其扩容机制进行了解,详情如下:

链接:Array的扩容操作,确实可以看到,无参构造之后,elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA,当第一次调用add()方法的时候,那么会将其扩容到容量为10;

如果看不懂,可以记得结果就行,就是确实是这么回事;同时,下面我也给出三个测试方法,也可以进行验证

 @Test

public void arrayListTest() throws Exception{

    ArrayList<Integer> arrayList = new ArrayList<>();

    Field elementData = ArrayList.class.getDeclaredField("elementData");

    elementData.setAccessible(true);

    Object[] obj = (Object[])elementData.get(arrayList);

    System.out.println(obj);

    ArrayList<Integer> arrayList1 = new ArrayList<>();

    Field elementData1 = ArrayList.class.getDeclaredField("elementData");

    elementData1.setAccessible(true);

    Object[] obj1 = (Object[])elementData1.get(arrayList1);

    System.out.println(obj1);

    arrayList1.add(1);

    Field elementData11 = ArrayList.class.getDeclaredField("elementData");

    elementData11.setAccessible(true);

    Object[] objects = (Object[])elementData11.get(arrayList1);

    System.out.println(objects);

    System.out.println(objects[0]);

    System.out.println(objects[9]);

    System.out.println(objects[10]);

}

    @Test

public void arrayListTest1() throws Exception{

    ArrayList<Integer> aa = new ArrayList<>();

    Field elementData11 = ArrayList.class.getDeclaredField("DEFAULTCAPACITY_EMPTY_ELEMENTDATA");

        elementData11.setAccessible(true);

    Object[] obj = (Object[])elementData11.get(aa);

    System.out.println(obj);

    ArrayList<Integer> ba = new ArrayList<>();

    Field elementData12 = ArrayList.class.getDeclaredField("DEFAULTCAPACITY_EMPTY_ELEMENTDATA");

    elementData12.setAccessible(true);

    Object[] obj1 = (Object[])elementData12.get(ba);

    System.out.println(obj1);

    System.out.println(obj1[0]);

    }

    

    @Test

public void arrayListTest2() throws Exception{

    ArrayList<Integer> arrayList = new ArrayList<>();

    Field elementData = ArrayList.class.getDeclaredField("elementData");

    elementData.setAccessible(true);

    Object[] obj = (Object[])elementData.get(arrayList);

    System.out.println(obj);

    System.out.println(obj[0]);

    }

分别运行,arrayListTest输出:

[Ljava.lang.Object;@e6ea0c6

[Ljava.lang.Object;@e6ea0c6

[Ljava.lang.Object;@6a38e57f

1

null

java.lang.ArrayIndexOutOfBoundsException: 10

arrayListTest1输出:

[Ljava.lang.Object;@e6ea0c6

[Ljava.lang.Object;@e6ea0c6

java.lang.ArrayIndexOutOfBoundsException: 0

arrayListTest2输出:

[Ljava.lang.Object;@e6ea0c6

java.lang.ArrayIndexOutOfBoundsException: 0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

这利用反射机制(正常别这样玩,这个很暴力),拿到了elementData,第一个例子里面可以看到,两次都是无参构造,然后分别取拿到elementData,输出,可以看到的是,两者的地址一致,再多几次也一样,并且,下面的第二个例子里面,也是利用反射机制拿到了DEFAULTCAPACITY_EMPTY_ELEMENTDATA,并且输出,第三个例子拿到elementData,可以发现这几个所指向的地址是一致的,也就是都是指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组的位置;同时,第三个例子里面输出obj[0](obj就是elementData),会报ArrayIndexOutOfBoundsException,所以再次验证了,刚刚无参构造的ArrayList就是一个空数组,并且在第一个例子中,当第一次调用add()方法时,我只调用了一次,然后输出objects[9]和objects[10],可以看到objects[9]不会报错,而objects[10],会报ArrayIndexOutOfBoundsException,也验证了第一次add操作之后,会构造出一个容量为10的数组,并且,数组的位置也会发生改变,因为在扩容过程中,进行了浅拷贝,elementData会重新指向那个新构造出来的数组。扩容具体实现可以看这篇,也是我写的:ArrayList底层原理及源码分析

最后再附上debug的截图,这里可以很清楚看到结果,和我上面用打印得到的结果一样,而且可以看到都是指向同一地方。

验证ArrayList无参构造时数组的容量

————————————————

验证ArrayList无参构造时数组的容量

原文链接:https://blog.csdn.net/weixin_43390562/java/article/details/101236959

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/4129.html

管理员

相关推荐
2025-06-07

在数字化阅读与实体书籍并存的时代,图书租赁管理系统正成为图书馆、书店及共享书吧提升运营效率的…

953
2025-06-07

在当今快节奏的校园生活中,外卖已成为学生和教职工日常生活中不可或缺的一部分。随着外卖需求的不…

997
2025-06-07

“金融市场瞬息万变,能否用Python实现同花顺自动化交易?” 这个问题,正是当下许多投资者和技术开发…

777
2025-06-07

你是否想过用中文编写一款高效、稳定的多用户聊天软件? 对于中小型团队或个人开发者而言,*易语言*…

1,018
2025-06-07

一、系统架构设计 分层架构: 前端层:用户端(H5/小程序/APP)+ 管理后台(Web) 服务层:抽奖核心…

674
2025-06-07

在数字化时代,二手交易市场正以前所未有的速度蓬勃发展。无论是闲置物品的流通,还是环保意识的提…

469
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号