java集合学习整理(1)

文章详细探讨了Java集合的重要性,特别是ArrayList的扩容机制。通过分析ArrayList的无参构造器创建过程,解释了元素添加时如何触发扩容,以及modCount参数的作用,说明了当集合大小变化时,modCount如何记录修改次数以防止并发修改异常。
摘要由CSDN通过智能技术生成

引用

本文部分图片源码文字来源于

1.java集合详解 - 不眠不休不写bug的文章 - 知乎 https://zhuanlan.zhihu.com/p/137999373

2.java中modCount 参数的用处http://t.csdn.cn/GvPDO

为什么需要集合?

java集合是什么?

java集合实际上是一种经常被运用到的java类库,其中提供了已经实现的的数据结构,省去了程序员再次编写数据结构的事情.在Leetcode中经常会被用到,有很重要的作用.

1.分类

Java中的集合一般分为两类:

一是继承了接口Collection的Set和List接口(单列集合),一是继承了Map接口的双列集合(存放的是键值对)。

img

2.List接口的底层操作扩容机制和源码(以ArrayList为例)

以一段非常简单的代码为例并进入debug
在这里插入图片描述

public class Main {
    public static void main(String[] args) {
        ArrayList pet = new ArrayList();
        pet.add("cat");
        pet.add("dogs");
        pet.add("cat");
        pet.add("goose");
        System.out.println(pet);
    }
}

在这里插入图片描述
在这里插入图片描述

调用无参构造器进行一个空的ArrayList对象的创建

(1)底层定义的参数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过断点进入后,在添加了一个对象时进入其底层源码。ArrayList在底层维护了一个Object类型的数组elementData,并且定义了一个默认大小为10的DEFAULT_CAPACITY。并且将默认的空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给elementData

之后进入第一个对象添加时的源码:

​ 首先可以从debugger看到关于这个ArrayList对象的一些基本信息:因为该集合为空,所以size=0,需要添加的字符串“cat”被传给了e对象。可以看到ArrayList类中的add方法传入一个类型为E(泛型)的e对象,进入了一个叫ensureCapacityInternal的方法,需要传进该方法的参数为 size+1**,此时为1,我们再次debug进入该方法:

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

再次进入方法**ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))中的calculateCapacity(elementData, minCapacity)**方法

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

在调用了无参构造器后第一个if判断值为真,进入方法Math.max(DEFAULT_CAPACITY, minCapacity),其中的DEFAULT_CAPACITY为类ArrayList的默认大小10,所以返回Math.max(10,1),即返回10.之后进入方法 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))其中传入的参数即为返回值10:

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

其中有一个参数modCount,在ArrayList的源码中并没有该参数的定义,所以我查阅了相关资料:

(2)modCount的含义:

img

大致的意思是:modCount这个参数记录了 某个List改变大小的次数,如果modCount改变的不符合预期,那么就会抛出异常。

好的了解了大概含义,我们继续进行源码分析:

  if (minCapacity - elementData.length > 0)
            grow(minCapacity);

其中的minCapacity就是传入的10,而elementData.length为数组elementData的长度,此时的elementData在前几步的操作中被赋为默认的空数组,所以其长度自然是0,满足此if的条件,所以进入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);
    }

其中的newCapacity经过操作 int newCapacity = oldCapacity + (oldCapacity >> 1)大小为oldCapacity的1.5倍,经过判断

if (newCapacity - minCapacity < 0)成立,此时将执行操作newCapacity = minCapacity,即该数组的新容量仍然为minCapacity,即此时的数组容量依然是够用的,不需要额外扩容,若(newCapacity - minCapacity < 0)不成立,则newCapacity为oldCapacity的1.5倍进行扩容。

最后将newCapacity的大小赋值给数组elementData的大小。即完成了底层数组的第一次扩容。

后继续进行add方法:

在这里插入图片描述

将e对象即传入的字符串赋值给elementData[size++],添加成功则返回true.

以上即为ArrayList的底层扩容机制。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值