集合框架-ArrayList底层结构和源码分析

1.ArrayList的主意事项

  • ArrayList可以加入null,并且可以多个

  • ArrayList是由数组来实现数据存储

  • ArrayList基本等于Vector,ArrayList是线程不安全的但是执行效率高,在多线程开发环境中不建议使用。

2.Arraylist的底层操作机制源码分析(重点、难点)

  • ArrayList中维护了一个Object类型的数组elementData

  • 源码:transient Object[] elementData; transient表示瞬间、短暂的,表示该属性不会被序列化

  • 当创建ArrayList对象时,如果使用的无参构造器则初始elementData容量为0,第一次添加,则扩容elementData为10,如需要再次扩充,则扩容以elementData的1.5倍扩容

  • 如果使用的是指定大小的构造器,初始elementData容量为指定大小,如果需要扩容则扩容以elementData的1.5倍扩容

3.无参构造创建ArrayList对象源码解读

创建对象时ArrayList无参构造直接给elementData一个空的Object数组

源码:

private static final Object[] EMPTY_ELEMENTDATA = {};这是一个Objec数组的静态常量

public ArrayList() {

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

第一次添加元素

先判断是否需要扩容后添加数据

源码:

public boolean add(E e) {

ensureCapacityInternal(size + 1); // Increments modCount!!

elementData[size++] = e;

return true;

}

private void ensureCapacityInternal(int minCapacity) {

ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

}

该方法确定minCapacity 第一次扩容10。 Math.max()方法返回一个最大值

源码:

private static final int DEFAULT_CAPACITY = 10;这是一个int静态常量

private static int calculateCapacity(Object[] elementData, int minCapacity) {

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

return Math.max(DEFAULT_CAPACITY, minCapacity);

}

return minCapacity;

}

modCount++记录集合被修改的次数 如果elementData大小不够就调用grow()去扩容

源码:

private void ensureExplicitCapacity(int minCapacity) {

modCount++;

// overflow-conscious code

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}

grow()方法真正执行扩容。使用扩容机制来确定要扩容多大,第一次newCapacity=10,第二次1.5倍扩容 往后以此类推 扩容使用的是Arrays.copyOf()方法。
源码:
int newCapacity = oldCapacity + (oldCapacity >> 1); 这里用到了右移运算 比如第二次扩容是相当于( 10+10*0.5=15 )1.5倍扩容就是这来的。
  • java移位运算小技巧
  • 左移一位相当于乘以2的1次方,左移n位就相当于乘以2的n次方。
  • 右移一位相当于除以2的1次方,右移n位就相当于除以2的n次方。
第一次扩容newCapacity相当于0+(0>>1) 0乘任何数还是0  所以会进入第一个if语句。并把minCapacity的值给到newCapacity
第二个if判断不会进去,MAX_ARRAY_SIZE的值很大
源码:

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

@Native public static final int MAX_VALUE = 0x7fffffff;0x7fffffff的值很大:2147483647

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

}

执行Arrays.CopyOf()完成扩容并把新内存地址给到elementData,

源码:

elementData = Arrays.copyOf(elementData, newCapacity);

之后的扩容就不会进入calculateCapacity() 方法的

if语句而是直接返回minCapacity

源码:

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

return Math.max(DEFAULT_CAPACITY, minCapacity);

}  

最后执行添加语句并返回一个布尔值

源码:

public boolean add(E e) {

ensureCapacityInternal(size + 1); // Increments modCount!!

elementData[size++] = e;

return true;

}

3.指定大小创建ArrayList对象
实例化对象是进行了if语句判断,如果大于0直接创建一个指定大小的Object数组,等于0后续代码依然走的无参构造的方式,其他情况抛出了一个非法参数异常( IllegalArgumentException)。

 源码:

public ArrayList(int initialCapacity) {

if (initialCapacity > 0) {

this.elementData = new Object[initialCapacity];

} else if (initialCapacity == 0) {

this.elementData = EMPTY_ELEMENTDATA;

} else {

throw new IllegalArgumentException("Illegal Capacity: "+

initialCapacity);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值