• 【JAVA - List类 - 啃烂ArrayList】ArrayList的源码分析及方法实现


    愿每个人都能遵循自己的时钟,做不后悔的选择

    在这里插入图片描述
    大家好,这里是新一,请多关照🙈🙉🙊。在本篇博客中,新一将会为大家介绍JAVA数据结构 - List源码分析及模拟实现,干货满满哟。(以下结果均在IDEA中编译)希望在方便自己复习的同时也能帮助到大家。😜😜😜🥇🥈🥉

    废话不多说,直接进入我们的文章。



    一.🌕 List的使用

    在这里插入图片描述
    👇👇👇
    List官方文档戳这里
    Array官方文档戳这里
    LinkedList官方文档戳这里

    1.1🍂 List常见方法

    在这里插入图片描述

    1.1.1 🍃 initialize && add

    public static void main(String[] args) {
            //初始化
            List<String> list1 = new ArrayList<>(20);
            ArrayList<String> list2 = new ArrayList<>();
    
            //添加元素
            list2.add("hello");
            list2.add("bit");
            list2.add("world");
            System.out.println(list2);
            System.out.println("========");
    
            //指定位置添加元素
            list2.add(0,"a");
            list2.add(4,"g");
            System.out.println(list2);
            System.out.println("========");
    
            //使用另外一个ArrayList对list3进行初始化,类型必须相同
            ArrayList<String> list3 = new ArrayList<>(list2);
            System.out.println(list3);
            System.out.println("========");
    
            //list3中尾插list2中的所有元素
            list3.addAll(list2);
            System.out.println(list3);
        }
    
    • 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

    在这里插入图片描述

    1.1.2 🍃 remove && clear

    public static void main(String[] args){
            //初始化
            ArrayList<String> list2 = new ArrayList<>();
    
            //添加元素
            list2.add("hello");
            list2.add("bit");
            list2.add("world");
            System.out.println(list2);
            System.out.println("========");
    
            //remove指定位置元素
            list2.remove(0);
            list2.remove(1);
            System.out.println(list2);
            System.out.println("========");
    
            //remove出现的第一个关键字
            list2.add("a");
            list2.add("bit");
            list2.remove("bit");
            System.out.println(list2);
            System.out.println("========");
            
            //clear 整个list
            list2.clear();
            System.out.println(list2);
        }
    
    • 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

    在这里插入图片描述

    1.1.3 🍃 get && set

    public static void main(String[] args) {
            //初始化
            ArrayList<String> list2 = new ArrayList<>();
    
            //添加元素
            list2.add("hello");
            list2.add("bit");
            list2.add("world");
            System.out.println(list2);
            System.out.println("========");
    
            //get 指定位置元素
            System.out.println(list2.get(0));
            System.out.println(list2.get(2));
            System.out.println("========");
    
            //set指定位置元素
            list2.set(0,"a");
            list2.set(2,"g");
            System.out.println(list2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    1.1.4 🍃 contains && indexOf

     public static void main(String[] args) {
            //初始化
            List<String> list = new ArrayList<>();
    
    
            //添加元素
            list.add("hello");
            list.add("bit");
            list.add("bit");
            list.add("world");
            System.out.println(list);
            System.out.println("========");
    
            //判断字段是否在线性表中
            System.out.println(list.contains("bit"));
            System.out.println("========");
    
            //返回字段所在的下标
            System.out.println(list.indexOf("bit"));//从头找
            System.out.println(list.lastIndexOf("bit"));//从尾找
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    1.1.5 🍃 subList

    public static void main(String[] args) {
            //初始化
            List<String> list = new LinkedList<>();
    
    
            //添加元素
            list.add("hello");
            list.add("bit");
            list.add("bit");
            list.add("world");
            System.out.println(list);
            System.out.println("========");
    
            //截取部分list - 左闭右开区间
            List<String> list1 = list.subList(0,1);
            System.out.println(list1);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    1.2🍂 List迭代器

    我们目前已知的LIST打印方法有两种:循环遍历toString方法,但除此之外我们还有迭代器打印:

    1.2.1 🍃 迭代器打印

    public static void main(String[] args) {
            System.out.println("=====toString===");
            ArrayList<String> list2 = new ArrayList<>();
            list2.add("hello");
            list2.add("bit");
            list2.add("haha");
            System.out.println(list2);
            
            System.out.println("====for..each===");
            for (String str:list2
                 ) {
                System.out.print(str + " ");
            }
            System.out.println();
            
            System.out.println("======for..=====");
            for (int i = 0; i < list2.size(); i++) {
                System.out.print(list2.get(i) + " ");
            }
            System.out.println();
            
            System.out.println("======迭代器=====");
            Iterator<String> it = list2.iterator();
            while (it.hasNext()){
                System.out.print(it.next() + " ");
            }
            System.out.println();
            
            System.out.println("==迭代器List用===");
            ListIterator<String> listIterator = list2.listIterator();
            while (listIterator.hasNext()){
                System.out.print(listIterator.next() + " ");
            }
    
        }
    
    • 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

    在这里插入图片描述

    1.2.2 🍃 迭代器比较

    我们通过查询官方文档可知,Iterator迭代器没有add方法,而ListIterator迭代器有add方法,两者的共同点是都有remove方法

    public static void main(String[] args) {
            ArrayList<String> list2 = new ArrayList<>();
            list2.add("hello");
            list2.add("bit");
            list2.add("haha");
    
            ListIterator<String> it = list2.listIterator();
            while (it.hasNext()){
                String ret = it.next();
                if (ret.equals("hello")) {
                    it.add("ag");//使用了迭代器修改list2其中元素,指针指向ag
                }else {
                    System.out.print(ret + " ");
                }
            }
            System.out.println();
            System.out.println(list2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    那么我们可不可以用ArrayList自己的add方法呢?

     public static void main(String[] args) {
            ArrayList<String> list2 = new ArrayList<>();
            list2.add("hello");
            list2.add("bit");
            list2.add("haha");
    
            ListIterator<String> it = list2.listIterator();
            while (it.hasNext()){
                String ret = it.next();//必须先迭代next所有元素,才能用remove删除
                if (ret.equals("hello")) {
                    list2.add("ag");
                }else {
                    System.out.print(ret + " ");
                }
            }
            System.out.println();
            System.out.println(list2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述
    此时我们发现代码报错了,这是因为我们的ArrayList线程不安全的,要想直接用对象的add方法,我们就只能用CopyOnWriteArrayList,它是线程安全

    public static void main(String[] args) {
            //ArrayList - 线程不安全 CopyOnWriteArrayList - 线程安全
            //ArrayList list2 = new ArrayList<>();
            CopyOnWriteArrayList list2 = new CopyOnWriteArrayList();
            list2.add("hello");
            list2.add("bit");
            list2.add("haha");
    
            System.out.println("==迭代器List用===");
            ListIterator<String> listIterator = list2.listIterator();
            while (listIterator.hasNext()){
                //用了CopyOnWriteArrayList抛异常
                String ret = listIterator.next();
                if (ret.equals("hello")) {
                    //listIterator.add("ag");
                    list2.add("ag");
                } else{
                    System.out.print(ret + " ");
                }
            }
            System.out.println();
            System.out.println(list2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述
    此时我们发现打印结果正确了;

    二.🌕 ArrayList源码分析

    2.1🍂 未初始化List空间大小分析

    不知道友友们想过一个问题没,当我们初始化不给定ArrayList空间时,它的默认空间是多少?0?

    ArrayList<String> list2 = new ArrayList<>();//0?
    
    • 1

    Ctrl + 点击ArrayList

    在这里插入图片描述
    我们此时看到它定义了一个10的常量,还定义了一个空数组,它没事儿定义它干嘛?这其中必有蹊跷,我们往下拉查看它的构造方法
    在这里插入图片描述
    谜底揭晓,但数组空间为0时,它就会将顺序表初始化为一个空间为0的数组,那么那个空间大小为10的常量是干嘛的?

    2.2🍂 add方法源码分析

    这就需要我们看看它的源码。看谁的?当然是add方法的,因为只有它添加元素时,才能看到其中的细节。

    Ctrl + 点击add

    在这里插入图片描述
    此处我们看到它实现了一个方法,然后直接就开始添加了??!!我们想它都不判满的吗?而满后我们前面实现的顺序表是用的copyOf进行扩容,这方法其中必有猫腻

    Ctrl + 点击ensureCapacityInternal

    在这里插入图片描述
    我们看到它传了一个方法的返回值到另一个方法中,我们先看看外内层方法是干嘛的
    Ctrl + 点击calculateCapacity
    在这里插入图片描述
    谜底揭晓,当我们添加元素时,数组空间才会被初始化为10,不添加元素,数组空间还是原先的0

    那么它是怎么扩容的呢?我们看看外层方法

    Ctrl + 点击ensureExplicitCapacity

    在这里插入图片描述
    我们看到它其中的if语句,如果传入的参数大于了数组长度执行方法grow

    Ctrl + 点击grow
    在这里插入图片描述
    终于我们看到了什么??!!Arrays.copyOf,至此我们便理解了ArrayList的add方法

    想对大家说的话

    家人们,学到这里我们的JAVA的List方法已经全部弄懂啦,🥳🥳🥳后续新一会持续更JAVA的有关内容,学习永无止境,技术宅,拯救世界!
    在这里插入图片描述

  • 相关阅读:
    wodP2P ActiveX 最新版 Crack
    【力扣】415. 字符串相加(大数相加)<模拟>
    弄懂性能测试指标,看再多不如这一篇
    图书管理系统(Java实现)[附完整代码]
    QT实现任意阶贝塞尔曲线绘制
    流媒体技术基础-摄像头接口与标准
    【ELK 使用指南 3】Zookeeper、Kafka集群与Filebeat+Kafka+ELK架构(附部署实例)
    一、C#委托、事件、Action、Func
    [Vue]路由传参 & 命名路由
    SpringBoot+Redis BitMap 实现签到与统计功能
  • 原文地址:https://blog.csdn.net/m0_73204758/article/details/126900731