Java实现ArrayList和底层源码讲解

这篇具有很好参考价值的文章主要介绍了Java实现ArrayList和底层源码讲解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Java实现ArrayList和底层源码讲解

🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!

欢迎志同道合的朋友一起加油喔🦾🦾🦾Java实现ArrayList和底层源码讲解


目录

一. 模拟实现ArrayList​编辑

1.定义顺序顺序表

2. 函数实现

(1) 打印顺序表display()函数

(2) 新增元素函数add() (默认在数组最后新增)

(3) 在 pos 位置新增元素add()函数(与上方函数构成重载)

(4) 判定是否包含某个元素contains()函数

(5) 查找某个元素对应位置indexOf() 函数

(6) 获取pos位置的元素get()函数

(7) 将pos位置的元素更新为value set()函数

(8) 删除第一个关键字key remove()函数

(9) 获得顺序表的长度size()函数

(10) 清空顺序表clear()函数

 (11) 异常的定义:

3.测试代码

二. ArrayList底层的扩容机制

三.顺序表的优缺点



 顺序表本质上就是一个数组,而顺序表就是实现对这个数组进行增删查改等操作方法的一个类,而Java中也有类似与顺序表的集合类:ArrayList<E> 下面我会对这个类里面比较重要且常用的方法进行实现。

一. 模拟实现ArrayList

我们这里是模拟实现,所以实现基本功能即可

Java实现ArrayList和底层源码讲解

1.定义顺序顺序表

public class MyArrayList{
 
    public int[] elem;
    public int usedSize;//目前存储元素个数
    //默认容量
    private static final int DEFAULT_SIZE = 10;
 
    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
    }
}

上方定义类SeqList即是顺序表,定义elem数组存储数据,定义usedSize表示当前数组中包含多少个元素,定义DEFAULT_SIZE值为了在构造方法中将顺序表初始化为DEFAULT_SIZE大小的数组。

2. 函数实现

(1) 打印顺序表display()函数

 打印函数顾名思义就是将顺序表中所有的数据打印出来。打印完的标准就是将顺序表中的数组完全输出,因此用usedSize作为终止条件,

public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            System.out.print(elem[i]+" ");
        }
        System.out.println();
    }

(2) 新增元素函数add() (默认在数组最后新增)

此函数是增加顺序表中元素的函数。增加元素时,有一点需要注意,你的顺序表是否含有空间放入新的元素。使用函数isFull()判断,若没有满就正常增加,若已满,先对顺序表扩容,再进行增加

 如何判断顺序表满没满?当数组的长度等于数组中包含元素就为满。

当数据载入顺序表成功后,数组中包含元素个数usedSize就需要加1。

public void add(int data) {
        if (this.usedSize == elem.length) {
            this.elem = Arrays.copyOf(elem, elem.length * 2;
        }
        elem[usedSize] = data;
        usedSize++;
    }

(3) 在 pos 位置新增元素add()函数(与上方函数构成重载)

我们要判断传过来的下标的合法性;分析pos的取值范围:我们要把新增函数放到现在已有元素之间,因此我们可以知道,pos的范围应该是 0<=pos<usedSize.若给定的下标不合法,我们就抛出一个异常,让程序停下来。

再者这个函数功能也是添加,因此我们也需要判断顺序表空间的问题。

若我们插入的位置已有元素,我们需把从pos位置的元素向后移,为data数据挪开位置。

当数据载入顺序表成功后,数组中包含元素个数usedSize就需要加1。

public void add(int pos, int data) {
        if (pos < 0 || pos > usedSize) {
            throw new ArrayIndexException("下标非法,请检查");
        }
        if (this.usedSize == elem.length) {
            this.elem = Arrays.copyOf(elem, elem.length * 2;
        }
        for (int i = usedSize - 1; i >= pos; i--) {
            elem[i + 1] = elem[i];
        }
        elem[pos] = data;
        usedSize++;
    }

 下面动图演示:

Java实现ArrayList和底层源码讲解

(4) 判定是否包含某个元素contains()函数

 拿到需要找的数据toValue,遍历数组,将数组中的所有值与toValue进行比较,若数组中的值有与toValue相等,那么就返回true,否则返回false。

public boolean contains(int toValue) {
        for (int i = 0; i < usedSize; i++) {
            if (elem[i] == toValue) {
                return true;
            }
        }
        return false;
    }

(5) 查找某个元素对应位置indexOf() 函数

同上方思想一致,拿到需要找的数据toValue,遍历数组,将数组中的所有值与toValue进行比较,若数组中的值有与toValue相等,那么就返回下标i,否则返回-1。

public int indexOf(int toValue) {
        for (int i = 0; i < usedSize; i++) {
            if (elem[i] == toValue) {
                return i;
            }
        }
        return -1;
    }

(6) 获取pos位置的元素get()函数

我们要判断下标是否合法,我们需要顺序表中的元素,因此pos不能超过顺序表中第一个元素的下标和最后一个元素的下标,即下标是0<=pos<usedSize,如果不在这个范围内,我们抛出一个异常,让程序停下来。

public int get(int pos) {
        if(pos<0||pos>=usedSize){
            throw new ArrayIndexException("下标非法,请查看!");
        }
        return elem[pos];
    }

(7) 将pos位置的元素更新为value set()函数

同上方一样,我们要判断下标是否合法,我们需要顺序表中的元素,因此pos不能超过顺序表中第一个元素的下标和最后一个元素的下标,即下标是0<=pos<usedSize,如果不在这个范围内,我们抛出一个异常,让程序停下来。最后将value赋到pos位置

public void set(int pos, int value) {
        if(pos<0||pos>=usedSize){
            throw new ArrayIndexException("下标错误,请查看!");
        }
        elem[pos] = value;
    }

(8) 删除第一个关键字key remove()函数

我们先调用indexOf()函数,判断顺序表中是否有我们删除的值,若有找到这个值的下标,没有就返回false。有就以覆盖的方式,将index下标的元素用他后一个元素覆盖,一直往复到最后一个元素,因为删除了一个元素,所以将usedSize减一,因为在覆盖时,最后一个元素是无效数据所以没有覆盖,我们将他置为0。

public boolean remove(int key) {
        int index = indexOf(key);
        if (index == -1) {
            System.out.println("没有这个数据");
            return false;
        }
        for (int i = index; i < usedSize - 1; i++) {
            elem[i] = elem[i + 1];
        }
        usedSize--;
        elem[usedSize] = 0;
        return true;
    }

 下面动图演示:

Java实现ArrayList和底层源码讲解

(9) 获得顺序表的长度size()函数

当前数组中包含多少个元素,顺序表就是多长,因此顺序表的长度就是usedSize的大小。

public int size() {
        return usedSize;
    }

(10) 清空顺序表clear()函数

因为所有的函数都是围绕这usedSisz进行构造的,我们只需将usedSize置为0,其他函数就无法进行运行(此处并非范例)

public void clear() {
        usedSize = 0;
    }

 (11) 异常的定义:

public class ArrayIndexException extends RuntimeException{
 
 
        public ArrayIndexException() {
        }
 
        public ArrayIndexException(String message) {
            super(message);
        }
}

3.测试代码



public class Test {
    public static void main(String[] args) {
        MyArrayList MyArrayList =new MyArrayList();
        //添加数据
        MyArrayList.add(1);
        MyArrayList.add(2);
        MyArrayList.add(3);
        MyArrayList.add(4);
        MyArrayList.add(5);
        //打印
        System.out.print("当前数组元素:");
        MyArrayList.display();
        //值所在的下标
        System.out.print("值所在的下标:");
        System.out.println(MyArrayList.indexOf(3));
        //是否包含这个值
        System.out.print("是否包含这个值:");
        System.out.println(MyArrayList.contains(2));
        //获得下标所在位置元素
        System.out.print("获得下标所在位置元素:");
        System.out.println(MyArrayList.get(3));
        //修改下标的值
        System.out.print("修改下标的值:");
        MyArrayList.set(3,12);
        MyArrayList.display();
        //删除关键字key
        System.out.print("删除关键字key:");
        MyArrayList.remove(2);
        MyArrayList.display();
        //获得长度
        System.out.print("获得当前顺序表长度:");
        System.out.println(MyArrayList.size());
    }
}

输出结果如下: 

Java实现ArrayList和底层源码讲解


二. ArrayList底层的扩容机制

ArrayList是一个动态类型的顺序表,即在插入元素的时候会自动扩容,下面是扩容机制:

Java实现ArrayList和底层源码讲解

Java实现ArrayList和底层源码讲解

🕯️总结:

✨当使用无参的构造方法创建ArrayList,容量默认值10在第一次插入的时候才会初始化初始容量,而不是在创建的时候就初始化容量

✨在插入时,会检测是否真正需要扩容,如果需要,调用grow扩容

✨初步预估按照原容量的1.5倍扩容
✨如果用户所需大小超过预估的1.5倍,则按照用户所需大小扩容
✨真正扩容之前检测是否能扩容成功,防止太大导致扩容失败

✨使用copyOf进行扩容 

三.顺序表的优缺点

 顺序表也是分情况使用的,如何判断呢?总结了它的优缺点,可以作为参考。

  优点:

  1. 无需为表示表中元素之间的逻辑关系而增加额外的存储空间。
  2. 可以快速地获取表中任意位置的元素。

  缺点:

  1. 插入和删除操作需要移动大量元素(时间复杂度高)。
  2. 当线性表长度变化较大时,难以确定存储空间的容量。
  3. 造成存储空间的“碎片”。(当我们添加元素时,例如我们有101个元素,数组初始大小为100,扩容为1.5倍,初始大小无法存储全部元素,因此需要扩容,扩容为150大小,这就浪费了49个空间)

Java实现ArrayList和底层源码讲解文章来源地址https://www.toymoban.com/news/detail-414809.html

到了这里,关于Java实现ArrayList和底层源码讲解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ArrayList 底层结构和源码分析

    ArrayList 实现了 List 接口。它可以存储包括 null 的任何类型的对象,允许重复元素。 ArrayList 在内部使用一个数组来存储元素,当元素数量超过数组容量时, ArrayList 会自动重新分配更大的内部数组,并且将现有元素复制到新数组中。 ArrayList 基本等同于 Vector ,但是 ArrayList 是

    2024年02月08日
    浏览(28)
  • 探秘ArrayList源码:Java动态数组的背后实现

    读者需先对源码的成员变量阅览一遍,看个眼熟,有助于后面源码的理解 以无参数构造方法创建 ArrayList时,实际上初始化赋值的是一个空数组。此时并没有为它创建对象,当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为

    2024年02月16日
    浏览(29)
  • ArrayList底层的实现原理

    ArrayList底层的实现原理 ArrayList底层是用动态数组实现的 ArrayList初始化容量为0,当第一次添加数据的时候才会初始化为10。 ArrayList在进行扩容的时候是原来容量的1.5倍,每次扩容都需要拷贝数组。 ArrayList在添加数据的时候 确保数组已使用长度size+1之后足够存下下一个数据 计

    2024年01月22日
    浏览(31)
  • 模拟ArrayList(顺序表)的底层实现

    2024年02月16日
    浏览(30)
  • Java:ArrayList集合、LinkedList(链表)集合的底层原理及应用场景

    入队 出队 压栈(push),addFirst可以替换成push,官方专门为压栈写了push的API 出栈(pop),removeFirst可以替换成pop,官方专门为出栈写了pop的API

    2024年02月12日
    浏览(30)
  • Java进阶(3)——手动实现ArrayList & 源码的初步理解分析 & 数组插入数据和删除数据的问题

    1.ArrayList的结构分析,可迭代接口,是List的实现; 2.数组增加元素和删除元素的分析,何时扩容,如何扩容; 3.插入数据的复杂度O(N); 4.数组特点:查找和修改容易O(1);增加和删除复杂O(N); 增加元素 如果放不下怎么办?如何扩容? 扩容后如何操作? 扩容:每次为原来的

    2024年02月12日
    浏览(32)
  • 深入分析Java中的PriorityQueue底层实现与源码

    本文分享自华为云社区《滚雪球学Java(70):深入理解Java中的PriorityQueue底层实现与源码分析》,作者: bug菌。 @[toc] PriorityQueue是Java中一个非常常用的数据结构,它可以实现基于优先级的排序,常用于任务调度、事件处理等场景。本文将深入探讨Java中PriorityQueue的底层实现与源

    2024年03月19日
    浏览(35)
  • Java集合框架之ArrayList源码分析

    ArrayList是Java提供的线性集合,本篇笔记将从源码(java SE 17)的角度学习ArrayList: 什么是ArrayList? ArrayList底层数据结构是怎么实现的? 作为一个容器,分析增删改查的过程 ArrayList的扩容机制 由ArrayList的定义可知,ArrayList继承了AbstractList抽象类,实现了List、RandomAccess、Cloneabl

    2024年02月07日
    浏览(46)
  • java源码----集合系列1----ArrayList,linkedList

    底层是一个object数组 Arraylist 是java里面Collection  标准的一个集合,其 底层是一个object数组 。当new一个空参的ArrayList的时候,会默认生成一个空数组。 Arraylist上限是 Integer.MAX_VALUE - 8(Integer.MAX_VALUE  =  2^31-1) ; 超过上限会报内存溢出 这里为什么是Integer.MAX_VALUE-8  ,源码上的解

    2024年02月03日
    浏览(32)
  • 【ArrayList】| 深度剥析Java SE 源码合集Ⅵ

    ArrayList ,基于 [] 数组实现的,支持 自动扩容 的动态数组。相比数组来说,因为其支持 自动扩容 的特性,成为我们日常开发中,最常用的集合类,没有之一。 ArrayList 实现的接口、继承的抽象类,如下图所示: 实现了 4 个接口,分别是: java.util.List 接口,提供数组的添加、

    2024年02月04日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包