吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1781|回复: 4
收起左侧

[Java 转载] java学习日记第三天(面试重点:常用集合ArrayList的源码解析)

[复制链接]
三木猿 发表于 2020-10-9 13:24
摸鱼的日子结束了,之后可能更新就慢了,不过学无止境,每学习一点都会发上来的ArrayList:
  • 初始容量,DEFAULT_CAPACITY是ArrayList的初始容量,其大小为10
image.png
  • size字段是ArrayList的大小,类型 int,没有使用 volatile 修饰,非线程安全的
image.png
  • modCount,这个变量在ArrayList的父类AbstractList中,数组被修改的版本次数,每次数组结构变化都会+1
image.png
  • 允许添加null,自动进行扩容(每次扩容增大1.5倍)
[Java] 纯文本查看 复制代码
   private void ensureCapacityInternal(int minCapacity) {
//如果初始化数组大小时,有给定初始值,以给定的大小为准,不走 if 逻辑
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
//确保容积足够
        ensureExplicitCapacity(minCapacity);
    }
    private void ensureExplicitCapacity(int minCapacity) {
//记录数组被修改
        modCount++;
// 如果我们期望的最小容量大于目前数组的长度,那么就扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    //扩容,并把现有数据拷贝到新的数组里面去
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
// oldCapacity >> 1 是把 oldCapacity 除以 2 的意思
        int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩容后的值 < 我们的期望值,扩容后的值就等于我们的期望值
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
// 如果扩容后的值 > jvm 所能分配的数组的最大值,那么就用 Integer 的最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            [url]https://www.imooc.com/read/47/article/847[/url] 3/11
                    2019/12/15 05 ArrayList 源码解析和设计思路 -慕课专栏
        newCapacity = hugeCapacity(minCapacity);
// 通过复制进行扩容
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

总的来说,ArrayList:
(1)扩容的规则并不是翻倍,是原来容量大小 + 容量大小的一半,直白来说,扩容后的大小是原来容量的 1.5 倍.
(2)源码在扩容的时候,有数组大小溢出意识,就是说扩容后数组的大小下界不能小于 0,上界不能大于 Integer 的最大值,这种意识我们可以学习。
(3)从上述可以看出ArrayList的扩容机制核心方法是Arrays.copyOf(elementData, newCapacity),把原本数组的内容移到新的数组设定长度,由此得出开发时
,如果知道数据的条数,创建ArrayList是应尽量设定数组长度,避免频繁的扩容
  • 再来看下最常用的add方法
    [Java] 纯文本查看 复制代码
    public boolean add(E e) {
    //确保数组大小是否足够,不够执行扩容,size 为当前数组的大小
    ensureCapacityInternal(size + 1); // Increments modCount!!
    //直接赋值,线程不安全的
    elementData[size++] = e;
    return true;
    }
  • 删除方法有很多,比如根据数组索引删除、根据值删除或批量删除等等,原理和思路都差不多,我们选取根据值删除方式来进行源码说明
[Java] 纯文本查看 复制代码
    public boolean remove(Object o) {
// 如果要删除的值是 null,找到第一个值是 null 的删除
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
// 如果要删除的值不为 null,找到第一个和要删除的值相等的删除
            for (int index = 0; index < size; index++)
// 这里是根据 equals 来判断值相等的,相等后再根据索引位置进行删除
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
//根据数组位置删除
    private void fastRemove(int index) {
// 记录数组的结构要发生变动了
        modCount++;
// numMoved 表示删除 index 位置的元素后,需要从 index 后移动多少个元素到前面去
// 减 1 的原因,是因为 size 从 1 开始算起,index 从 0开始算起
        int numMoved = size - index - 1;
        if (numMoved > 0)
// 从 index +1 位置开始被拷贝,拷贝的起始位置是 index,长度是 numMoved
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
//数组最后一个位置赋值 null,帮助 GC
        elementData[--size] = null;
    }    }

我们需要知道的是,只有当 ArrayList 作为共享变量时,才会有线程安全问题, ArrayList 是方法内的局部变量时,是没有线程安全的问题的
ArrayList 有线程安全问题的本质,是因为 ArrayList 自身的 elementData、size、modConut在进行各种操作时,都没有加锁而且这些变量的
类型并非是可见(volatile)的,所以如果多个线程对这些变量进行操作时,可能会有值被覆盖的情况。
如果一定要保证线程安全的话可以用Collections包中的synchronizedList,它的原理是在方法中加入synchronized来保证线程安全,如下:
[Java] 纯文本查看 复制代码
public boolean add(E e) {
synchronized (mutex) {// synchronized 是一种轻量锁,mutex 表示一个当前 SynchronizedList
return c.add(e);
}
}

这篇文章中有进行ArrayList的简单性能测试↓
一起讨论如何提高代码质量
https://www.52pojie.cn/thread-1265319-1-1.html
(出处: 吾爱破解论坛)



免费评分

参与人数 7吾爱币 +6 热心值 +7 收起 理由
Q_Clown + 1 + 1 我很赞同!
夏橙M兮 + 1 + 1 谢谢@Thanks!
allunw + 1 热心回复!
4665 + 1 + 1 用心讨论,共获提升!
小鱼干! + 1 + 1 热心回复!
于洪生 + 1 + 1 热心回复!
张小凡。 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

HWW0713 发表于 2020-10-9 15:44
我的天,才第三天,楼主竟然看懂了。。。。
 楼主| 三木猿 发表于 2020-10-9 15:46
HWW0713 发表于 2020-10-9 15:44
我的天,才第三天,楼主竟然看懂了。。。。

别误会,不是初学者的第三天,我个人的学习日记,写到第三天
testicles 发表于 2020-10-12 18:47
alonelyking 发表于 2020-10-13 19:00
向楼主学习,,不过我现在学的java基础都还没学多少
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 23:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表