2020-12-30

年轻人不讲武德,一起聊聊List集合(三)

文章目录

  • 前言
  • 一、List类图
  • 二、源码剖析
    • 1. Vector(此篇详解)
    • 2. ArrayList
    • 3. LinkedList
    • 4. CopyOnWriteArrayList
  • ~~   码上福利


前言

业精于勤荒于嬉,行成于思毁于随;

在码农的大道上,唯有自己强才是真正的强者,求人不如求己,静下心来,开始思考…

今天一起来聊一聊 List集合,看到这里,笔者懂,大家莫慌,先来宝图镇楼 ~
在这里插入图片描述
年轻人,不讲武德,敢偷袭我老同志,耗子尾汁…

咳咳… 相信大家满脑子的ArrayList已被保国爷爷经典的画面以及台词冲淡了,那么,目的已达到,那我们言归正传,对于屏幕前帅气的猿友们来说,ArrayList,LinkedList,Vector,CopyOnWriteArrayList… 张口就来,闭眼能写,但是呢,我相信大部分的猿友们并没有刨根问底真正去看过其源码,此时,笔者帅气的脸庞似有似无洋溢起一抹微笑,毕竟是查看过源码的猿,就是那么的不讲武德,吃我一记闪电五连鞭,话不多说,来吧,展示…



一、List类图

List全家桶



二、源码剖析


1. Vector(此篇详解)


在讲Vector集合之前呢,有必要嘱咐屏幕前的猿友一声,其实呢,Vector集合与ArrayList集合基本类似,但也存在差异,重点在于其对应构造以及新增、获取、删除方法,一定要认真仔细观阅,希望再文章末尾,猿友们已自行找出其两者异同点;

  • 构造函数
    // Vector底层为数组
    protected Object[] elementData;
// 自定义扩容增量
protected int capacityIncrement;

/**
 * 无参构造
 */
public Vector() {
    this(10);
}

/**
 * 有参构造一
 * @param initialCapacity:指定数组初始容量
 */
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}


/**
 * 有参构造二
 * @param initialCapacity
 * @param capacityIncrement:指定自定义扩容增量,后续扩容中有具体体现
 */
public Vector(int initialCapacity, int capacityIncrement) {
    // 父类AbstractList无参构造 - 无具体实现
    super();

    // 数组初始容量校验
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                initialCapacity);

    // 初始化数组 - length:10
    this.elementData = new Object[initialCapacity];
    
    // 设置自定义扩容增量
    this.capacityIncrement = capacityIncrement;
}
  • 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

从源码中可以看出,上述构造方法中,不论是无参构造方法,还是有参构造方法一最终都会调用有参构造方法二,其包含两个参数(initialCapacity:数组初始容量,capacityIncrement:自定义扩容增量);

结论:
构造初始化对象,初始化数组,默认length为10,自定义扩容增量默认为0;

  • add() - 添加元素方法
    // 记录对Vector操作次数
    protected transient int modCount = 0;
// 记录数组元素个数
protected int elementCount;

// Vector最大元素个数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
 * 入口 - synchronized修饰:线程安全
 */
public synchronized boolean add(E e) {
    // 操作次数++
    modCount++;
    // 对数组进行扩容
    ensureCapacityHelper(elementCount + 1);
    // 数组添加元素
    elementData[elementCount++] = e;
    return true;
}

// 判断是否需要进行扩容 minCapacity:第一次add为(0+1)=1
private void ensureCapacityHelper(int minCapacity) {
    // 最小容量-数组长度>0:需要进行扩容
    // 第1次add时:1-10 < 0,无需扩容
    // 第11次add时:11-10 > 0,需进行扩容
    if (minCapacity - elementData.length > 0) {
        // 具体扩容方法
        grow(minCapacity);
    }

}

// 具体扩容方法
private void grow(int minCapacity) {
    // 获取数组长度
    int oldCapacity = elementData.length;
    // 计算新的数组容量;capacityIncrement:自定义扩容增量,用户可通过有参构造自定义其值,默认为0
    // 当用户自定义capacityIncrement且值大于0,扩容后数组容量为:数组长度+capacityIncrement
    // 反之(包含:用户自定义但值<=0 或 用户未定义),扩容后数组容量为:数组长度+数组长度,即扩容后为之前数组长度的2倍
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
    // 判断如果扩容后长度-最小容量<0,扩容后的长度为最小容量,此判断作用于第一次添加元素时
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 计算扩容后长度最大值,最大值为Integer的最大值(2^31-1)
    if (newCapacity - MAX_ARRAY_SIZE > 0) {
        if (minCapacity < 0)
            throw new OutOfMemoryError();
        newCapacity = (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }

    // 使用 Arrays.copyOf 对我们数组容量实现扩容
    elementData = Arrays.copyOf(elementData, newCapacity);
}
  • 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

从源码中可以看出,添加元素时且会对数组进行扩容;

知识点:
第一次扩容是在第11次add时,此时分为两种情况:

  • 1.用户自定义capacityIncrement且值大于0时:数组长度扩容为(当前数组长度+capacityIncrement),之后每次扩容遵循此规则;
  • 2.用户未定义capacityIncrement(代表默认情况下) 或 用户自定义capacityIncrement且值小于等于0时:数组长度扩容为(当前数组长度+当前数组长度),之后每次扩容遵循此规则;

结论:
默认情况下,每次扩容后为之前数组长度的2倍;
最大值:Integer最大值(2^31-1),最小值:10;


  • get() - 获取元素方法
    /**
     * 入口 - synchronized修饰:线程安全
     */
    public synchronized E get(int index) {
     
        // 校验是否越界
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
    // so easy:通过下标获取元素
    return elementData(index);
}

// 通过下标获取元素
E elementData(int index) {
    return (E) elementData[index];
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

从源码中可以看出,获取元素时就是获取数组元素,通过下标直接获取即可;


  • remove() - 删除元素方法
    /**
     * 入口 - synchronized修饰:线程安全
     */
    public synchronized E remove(int index) {
     
        // 操作次数++
        modCount++;
    // 校验下标是否越界
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    // 获取要删除的元素
    E oldValue = elementData(index);

    /**
     * public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
     *  说明此方法参数作用:
     *      src:源数组
     *      srcPos:源数组要复制的起始位置
     *      dest:目的数组
     *      destPos:目的数组放置的起始位置
     *      length:复制的长度
     */
    // 对应参数中length
    int numMoved = elementCount - index - 1;
    // 删除元素其实就是一个数组整体移动的过程,再将最后一个元素置空即可
    if (numMoved > 0) {
        // 此每个参数都需各位猿友细品下,慢慢来,只是一个过程... 如此如此,这般这般,暖男的我在下方提供图,便于猿友们理解
        System.arraycopy(elementData, index+1, elementData, index, numMoved);
    }

    // 将最后一个元素置空,如只有一个元素,置空即可,便于GC工作
    elementData[--elementCount] = null; // Let gc do its work

    // 返回删除的元素值
    return oldValue;
}
  • 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

相信猿友们已经看出来了,Vector的删除元素方法与ArrayList的删除元素方法是一样的,而且除了删除元素方法,其增加元素方法、获取元素方法也都是很相似的;

从源码中可以看出,删除元素实则为数组移动覆盖的过程,已下图为例,便于大家理解:

  • 源数组:
    源数组
  • 目标数组(删除元素后的数组):
    目标数组
  • 删除下标为0的元素(不)

结合 arraycopy(Object src, int srcPos, Object dest, int destPos, int length)来讲,可得知:

  1. src:为上述源数组;
  2. srcPos:源数组要复制的起始位置为(index+1 = 0+1 = 1)
  3. dest:为上述目标数组
  4. destPos:目标数组放置的起始位置为(index=0);
  5. length:复制的长度为(size-index-1 = 4-0-1 = 3)
  • 过程演示:
    过程演示
  • 划重点:

相信之前没仔细研究过的猿友们,对Vector删除元素大概过程已有一些了解;

但对于有经验的开发猿来说,笔者大概能猜到两种,一种是一心追随本心道心坚固的猿友,另一种呢就是追求大道审视局势的猿友;

前者:看到这里,不论是从笔者的描述还是图文结合的理解,貌似有一定的道理,但当时的我看并不是如此,既然是arraycopy,那就不应该是移动覆盖,而是重新复制一个新数组。

后者:我当时查阅源码好像觉得也并不是这样的,记得也是复制一个新数组,而不是移动覆盖。但笔者描述确又很在理,难道…遗漏了什么?

邪魅一笑,嘴角微起,来吧,展示…
删除元素源码
其实嘛,大家说的都没错,实际上确实是复制新的数组,但Vector这里,源数组和目标数组是用一个呢.

哎…人生么,如此这般,细节决定成败。

  • Vector总结:
  1. 底层为数组;
  2. 构造初始化,数组为空数组,集合size为0,数组length为0;
    第一次扩容也就是第11次add时:默认情况下,数组长度length扩容为20,集合size为11;
    默认情况下,之后每次扩容遵循此规则,oldCapacity + oldCapacity,故每次扩容为之前数组长度的2倍;
    最大值:Integer最大值2147483647(2^31-1),最小值:10;
  3. 通过下标去获取元素,故查询效率高,增删效率低;
  4. 线程安全;
  5. 有modCount;


2. ArrayList

不讲武德,一起聊聊List集合之ArrayList


3. LinkedList

不讲武德,一起聊聊List集合之LinkedList


4. CopyOnWriteArrayList

不讲武德,一起聊聊List集合之CopyOnWriteArrayList



~~   码上福利


大家好,我是猿医生:

在码农的大道上,唯有自己强才是真正的强者,求人不如求己,静下心来,扫码一起学习吧…
https://marketing.csdn.net/poster/145?utm_source=765669642

年轻人 武德一起 聊聊 List 集合(一)
猿医ˉ生
12-24 7645
文章目录前言一、 List类图二、源码剖析1. Array List(此篇详解)2. Linked List3. Vector4. CopyOnWriteArray List~~   码上福利

前言
业精于勤荒于嬉,行成于思毁于随;
在码农的大道上,唯有自己强才是真正的强者,求人不如求己,静下心来,开始思考…
今天一起来聊一聊 List集合,看到这里,笔者懂,大家莫慌,先来宝图镇楼 ~

我要打十个年轻人,敢偷袭我老同志,耗子尾汁…
咳咳… 相信大家满脑子的ArrayList已被保国爷爷经典的画面以


年轻人 武德一起 聊聊 List 集合
qq_2580123的博客
12-27 31
一、 List类图

二、源码剖析

ArrayList(此篇详解)

构造函数
// 默认值-空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// ArrayList底层为数组 transient关键字:当前数组不能被序列化
transient Object[] elementData;

/**

  • 构造函数
    */
    public ArrayList() {
    this.elementData =

  • <
  • 1
  • >
年轻人 武德一起 聊聊 List 集合(二)
猿医ˉ生
12-25 730
文章目录前言一、 List类图二、源码剖析1. Linked List(此篇详解)2. Array List3. Vector4. CopyOnWriteArray List~~   码上福利

前言
业精于勤荒于嬉,行成于思毁于随;
在码农的大道上,唯有自己强才是真正的强者,求人不如求己,静下心来,开始思考…
今天一起来聊一聊 List集合,看到这里,笔者懂,大家莫慌,先来宝图镇楼 ~

蓝白黑相间的格子衫,正酝酿着闪电鞭法之五连鞭,说时迟,那时快,敢偷袭我老同志,大意了,没有闪,耗子尾汁…
咳咳…


年轻人 武德!卢伟冰脱口秀:小米高端之路好自为之
大力财经
11-27 815
11月26日,Redmi正式发布千元精品Note系列新机,三剑齐发:Note 9 Pro、Note 9和Note 9 4G三款产品。

Redmi Note 9 Pro国内首发旗舰规格的一亿像素相机HM2,首发高通骁龙750G液冷游戏芯,同时配备120Hz变速高刷新率屏幕。

Note 9采用性能强劲的天玑800U处理器,5000mAh充电宝级大电池和4800万三摄。

Note 9 4G采用6000mAh长循环电池,配备128GB大内存。Note 9系列全系搭载立体声双扬声器和首发UFS2.2内存,售价9


年轻人 武德,免费分享的白嫖字节技术专家的JDK源码手册,耗子为汁
12-24
本文将从多线程基础知识 起,逐步地深入整个Concurrent包。读完本书,你将对多线程...5.6 ConcurrentSkip ListMap/Set 第6章 线程池与Future 6.1 线程池的实现原理 ...
年轻人 武德?12月19日来3306π深圳站学点真本事_老...
12-18
转眼到了2020年的尾声,3306π也将移步深圳站,深圳站作为3306π的传统年会站,本次分享阵容依然强大,有MySQL官方、金融银行、一线互联网、一线云厂商等等。小编也给...
年轻人 武德,竟用Python让马老师表演闪电五连鞭!
爬遍所有网站
11-27 1204
11月份的头条,是属于马保国的。

一位69岁的老同志,惨遭年轻人偷袭,不武德

看看把老同志欺负的…

要不是马老师仁义道德,甩手就是一个五连鞭。

哈哈哈,所以本期我们就用Python给马保国老师做一个闪电五连鞭动态词云图。

词云数据来自B站,使用stylecloud词云库绘制。

主要参考百度AI Studio上的一个开源项目,使用PaddleSeg对人像进行分割。

年轻人,不武德。这样好吗,耗子尾汁。

PS:如有需要Python学习…


SpringBatch - MetaData, 年轻人 武德
current_person的博客
11-28 471
前言 马保国男神, 混元形意太极拳掌门人, 在一次比武中, 年轻人 武德, 说打就打, 大意了没有闪而没有使出闪电五连鞭而被大家嘲讽 Spring Batch 统计性 在定时任务的运行过程中, 需要统计一些基本的数据, 比如本次运行的定时任务的入参, 任务读取, 处理, 跳过, 失败, 写入的次数这些关键数据 Spring Batch 例子 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 我们先定义一个数据源: @Configuration public class DataSour
面试官: 年轻人你不 武德!面试大厂之前竟然刷了这份Git...
12-27
说说 List,Set,Map三者的区别 Array与Array List有什么不一样? Map有什么特点 集合内存放于 Java.util 包中, 主要有几 种接口 什么是 list接口 ...
年轻人 武德,刁难Java面试官:B+树如何实现索引?最后...
12-26
得亏当时是电面,要不然我都不知道用什么样的表情面对面试官!哈哈哈! 我觉得面试官当时肯定心想: 年轻人 武德,偷袭我69岁面试官?
卧槽,这 年轻人 武德,应届生凭“小抄”干掉5年老鸟,成功拿到字节20Koffer
Javayinlei的博客
11-26 9466
说来刺激,应届生KK在字节终面上干掉了985院校背景、5年经验的编程老鸟,狂揽20K offer。 这源于他在阿里上班的表哥给他拿到的一份阿里面试手册,里面有各种面试解题模板。

在字节面试中,他遇到了一道他在《阿里面试手册》看到过的原题。这个手册里面的题目包含了互联网大厂常问的面试题,其中这题近半年在字节跳动算法面试环节出现频率高达10次以上。当时还不相信,没想到真的有狗屎运。立马套用了“万金油”解题模板秒掉了对手。

点击此处免费领取该手册:暗号CSDN

BAT一线大厂算法小抄,点击此处免费领取


  【算法百题之三十九】 年轻人 武德,5分钟学会A*算法
cooclc的博客
12-02 729
【算法百题之三十九】 年轻人 武德,5分钟学会A*算法

大家好,我是Lampard~~

很高兴又能和大家见面了,接下来准备系列更新的是算法题,一日一练,早日升仙!

今天的探讨的问题是:实战8方向A*寻路算法。

【A*入门博客1】

【A*入门博客2】

若对A概念不熟悉的年轻人们可以先看看上面两篇博客,我觉得概念解释得很不错的。今天主要和大家一起代码实战A,先上效果图:

(1)A*算法的主要构成

在我看来,…


年轻人 武德有多可怕?_数据与算法之美
12-13
2 这都是什么阴间燃料 (素材来源网络,侵删) ▼ 3 年轻人 武德 (素材来源网络,侵删) ▼ 4 当你偷瞄喜欢的男生 ▼ 5 贝多芬:我入土这么都多年了 ...
年轻人 武德!Security五套「源码级」笔记哪里来的...
11-24
这三个模块分别在Spring Security5.0、5.1和5.3三个版本中被集成,原有的独立项目则进入维护状态。. Spring Security 5.0中集成了OAuth的客户端模块,该模块包含...
年轻人 武德,竟然想白嫖我的开发神器
csdncopy的博客
11-26 600
大家好,我是白码王子,糖糖。

今天有个同学问我:公司要开发一个流程,没有思路,问我有没有比较好的方法然后啪啪给我一张图。

大概类似于这样式儿

我一看,哟,财务审批流程,这一点一点儿写的话需要挺久,由于是.net程序员,我推荐他使用ccflow框架,功能强,写起来还算方便。

但是,这小子竟然说项目比较急,有没有马上能做出来的东西,因为自己不足以在这么短的时间写出来。

小样儿,有想法,看样子是时候拿出我的开发神器了。

来来来,瞅一瞅,看一看。

这个怎么用?

这个简单,代码都不用,直接把流


年轻人 武德,竟然重构出这么优雅后台 API 接口
程序员麦冬的博客(公众号同名)
11-27 672
最近偶然间在看到 Spring 官方文档的时候,新学到一个注解 @ControllerAdvice,并且成功使用这个注解重构我们项目的对外 API 接口,去除繁琐的重复代码,使其开发更加优雅。 展示具体重构代码之前,我们先来看下原先对外 API 接口是如何开发的。 这个 API 接口主要是用来与我们 APP 交互,这个过程我们统一定义一个交互协议,APP 端与后台 API 接口统一都使用 JSON 格式。 另外后台 API 接口对 APP 返回时,统一一些错误码,APP 端需要根据相应错误码,在页面弹出一些
年轻人!不 武德!_漫话编程的博客
12-8
年轻人!不 武德! 了不起的程序员---原创出品 - 我是个程序员 也曾是个秀发浓密的程序员 但如今看着镜中光亮如新的自己 突然思绪万千 ... - 生活从不...
年轻人 武德,竟然重构出这么优雅后台 API 接口_纯洁...
11-27
每天早上七点三十,准时推送干货 Hello,早上好,我是阿粉~ 最近偶然间在看到 Spring 官方文档的时候,新学到一个注解@ControllerAdvice,并且成功使用这个注解重构我们...
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页

热门文章

  • 5分钟学会MySQL-this is incompatible with sql_mode=only_full_group_by错误解决方案 210344
  • 5分钟学会swagger配置 18881
  • 5分钟学会Linux编辑文件命令 17679
  • 5分钟学会Layer.open()使用post提交方式传参 16766
  • 5分钟学会Redis实现消息队列 13760

分类专栏

  • 集合源码系列 4篇
  • 笔记 1篇
  • java设计模式 6篇
  • 大厂面试集锦 1篇
  • 并发编程系列 1篇
  • mybatis源码剖析 1篇
  • GIT系列 2篇
  • mysql系列 11篇
  • linux部署系列 9篇
  • mybatis系列 3篇
  • Web系列 2篇
  • Linux系列 16篇
  • springboot系列 8篇
  • java系列 6篇
  • mysql存储过程 8篇
  • ajax系列 1篇
  • 页面静态化系列 3篇
  • quartz定时器系列 1篇
  • redis系列 3篇
  • 个人系列 1篇
  • 闲来笔记 5篇
  • JS/JQ系列 8篇
  • JVM系列 2篇

最新评论

  • 年轻人不讲武德,一起聊聊List集合(三)

    水巷石子: 文章很赞,作者辛苦了!

  • 年轻人不讲武德,一起聊聊List集合(一)

    大团猿: 大佬写的太棒了!支持多更!

  • 年轻人不讲武德,一起聊聊List集合(三)

    strive_day: 分析的很到位,学到了很多,谢谢分享!

  • 年轻人不讲武德,一起聊聊List集合(四)

    帝都的雁: 细,不多说

  • 年轻人不讲武德,一起聊聊List集合(三)

    雾进: 反手就是一个赞!

最新文章

  • 年轻人不讲武德,一起聊聊List集合(四)
  • 年轻人不讲武德,一起聊聊List集合(二)
  • 年轻人不讲武德,一起聊聊List集合(一)
2020年 17篇
2019年 41篇
2018年 32篇

目录

  1. 文章目录
  2. 前言
  3. 一、List类图
  4. 二、源码剖析
    1. 1. Vector(此篇详解)
    2. 2. ArrayList
    3. 3. LinkedList
    4. 4. CopyOnWriteArrayList
  5. ~~   码上福利

你可能感兴趣的:(集合源码系列,java)