吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1846|回复: 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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   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] 纯文本查看 复制代码
    1
    2
    3
    4
    5
    6
    7
    public boolean add(E e) {
    //确保数组大小是否足够,不够执行扩容,size 为当前数组的大小
    ensureCapacityInternal(size + 1); // Increments modCount!!
    //直接赋值,线程不安全的
    elementData[size++] = e;
    return true;
    }
  • 删除方法有很多,比如根据数组索引删除、根据值删除或批量删除等等,原理和思路都差不多,我们选取根据值删除方式来进行源码说明
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    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] 纯文本查看 复制代码
1
2
3
4
5
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, 2025-4-16 11:30

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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