• 深度解析ArrayList使用


    在这里插入图片描述

    一、ArrayList是什么?

    ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。ArrayList 继承了 AbstractList ,并实现了 List 接口。
    在这里插入图片描述

    在这里插入图片描述
    我们发现ArrayList类位于java.util包中,使用之前需要去引入它.

    import java.util.ArrayList;
    
    • 1

    ArrayList如何定义:

    ArrayList<E> arrayList = new ArrayList<E>();
    
    • 1

    此数E为泛型实参类型,只能为引用数据类型,ArrayList想存储什么类型的数据,我们就传什么就可以。

    List<E> list = new ArrayList<E>();
    
    • 1

    因我们的ArrayList是继承于List的,所以我们可以用父类去接受子类对象,向上转型

    二、ArrayList的构造方法

    在这里插入图片描述
    我们发现ArrayList一共提供了三种构造方法。
    构造方法1:
    构造一个空的顺序表

            List<Integer> list = new ArrayList<>();
    
    • 1

    构造方法2:
    构造一个指定大小为5的顺序表

            List<Integer> list = new ArrayList<>(5);
    
    • 1

    构造方法3:
    在这里插入图片描述
    此处传入的要么是自己本身类型,或者是子类类型。
    此处构造一个和list2元素一致的顺序表

            List<Integer> list2 = new ArrayList<>(5);
            List<Integer> list = new ArrayList<>(list2);
    
    • 1
    • 2

    初始时的坑

    List list = new ArrayList();
    
    • 1

    这样对顺序表进行初始化的话,没有指定任何类型,这样的话可以存放任意类型的元素,这样会存在很大的安全隐患。

    三、ArrayList的常见方法

    常见方法

    在我的上一篇实现顺序表中,已经把大多数方法手动实现了一遍,此处我在说明几个重点的。
    在这里插入图片描述
    remove方法
    ArrayList提供给我们两个remove方法
    在这里插入图片描述
    一个是传入要删除的下标,一个是要删除的引用。

    public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(10);
            list.add(8);
            list.remove(1);
            System.out.println(list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果我们传入的是int类型那么我们删除的是该下标的数据。
    在这里插入图片描述

    public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(10);
            list.add(8);
            list.remove(new Integer(10));
            System.out.println(list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果我们传入的是引用数据类型,那么将删除该顺序表中的该引用数据。
    在这里插入图片描述
    subList方法

    public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            System.out.println("截取之前的list:"+list);
            List<Integer> list1 = list.subList(1,3);
            list1.set(0,5);
            System.out.println("截取之后的list:"+list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    为啥改了list1之后,list的数据也发生了变化。
    在这里插入图片描述
    因为在截取之后并没有复制一份内容给list1,而是指向同一块内容。

    遍历ArrayList

    方法1:

    public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            for (int i = 0; i < list.size(); i++) {
                System.out.print(list.get(i)+" ");
            }
            System.out.println();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    方法2:

    public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            for (Integer x:list) {
                System.out.print(x+" ");
            }
            System.out.println();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    方法3:
    使用迭代器
    在这里插入图片描述

    方法作用
    .next()返回迭代器写一个元素,更新迭代器状态
    .hasNext()检测集合中是否还有元素
    .remove()将迭代器返回的元素删除
    public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            Iterator<Integer> it = list.listIterator();
            while (it.hasNext()) {
                System.out.print(it.next()+" ");
            }
            System.out.println();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    使用迭代器删除元素

    我们删除集合小于3的元素

    public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            Iterator<Integer> it = list.listIterator();
            while (it.hasNext()) {
                if(it.next() < 3) {
                    it.remove();
                }
            }
            System.out.println(list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    迭代器的remove方法只能删除当前指向的元素。

    四、ArrayList的扩容机制

    List<Integer> list = new ArrayList<>();
    
    • 1

    很多资料都在说这样初始化一个集合,说默认大小为10,那事实到底是不是如此呢?我们一步步查看源码一探究竟。

    在这里插入图片描述
    我们发现当前引用指向后面那个引用
    在这里插入图片描述
    我们发现这里的引用是一个空引用,初始集合时,是一个空集合
    那如何扩容呢?
    既然我们的顺序表是空的,那如何add呢?
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    如果是无参构造的话,就传一个默认大小和传入大小的最大值。
    在这里插入图片描述
    我们可以发现如果大于数组大小时,就会grow。
    在这里插入图片描述
    我们可以发现计算一个新容量,和我们传入的大小做比较,如果新容量小于传入的大小时,指定当前集合大小为传入的大小。否则,对集合大小进行1.5倍扩容。
    在这里插入图片描述
    但如果我们1.5倍扩容的大小超过了这个指定的范围2147483639时
    在这里插入图片描述
    系统会报一个内存溢出异常。

    1. 检测是否真正需要扩容,如果是调用grow准备扩容
    2. 预估需要库容的大小
    初步预估按照1.5倍大小扩容
    如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
    真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
    3. 使用copyOf进行扩容

  • 相关阅读:
    javascript 基本语法(二)
    学了一天java,我总结了这些知识点
    0.Linux环境搭建
    股票量化择时策略(1)
    排序算法-合并排序法(MergeSort)
    机器学习周记(第四十三周:MCformer)2024.6.10~2024.6.16
    并查集
    2、HTML常用标签
    html中css的基础学习
    LNMP架构介绍及配置--部署Discuz社区论坛与wordpress博客
  • 原文地址:https://blog.csdn.net/buhuisuanfa/article/details/126926645