【数据结构/Java】ArrayList的底层实现和使用方法

👽 博客主页:<芝士盘盘>
❤️‍🔥💗💓一键三连:👍 点赞 ✌️ 收藏 👌 关注
👻小小勉励:当一个人的心专注在一桩事情上的时候,这种热情是意义深重的。——马克吐温
在这里插入图片描述

一.何为ArrayList

Implements
Extends
Implements
Implements
Implements
Extends
Implements
Extends
Implements
ArrayList
RandomAccess
AbstractList
Serializable
Cloneable
List
AbstractCollection
Collection

用官方的话来说ArrayList就是动态数组🔍,用MSDN中的说法,就是Array的复杂版本,它提供了动态的增加和减少元素,实现了ICollection🔍IList🔍接口,灵活的设置数组的大小等好处。
通俗来讲,就是Java为了实现顺序表这一数据结构而完成的一个集合类🔍,底层使用一个动态数组来实现,并且这个类下包装了操作这个数组的各种方法供用户使用,这个类叫做ArrayList。

二.ArrayList的底层实现

注:接下来附有底层实现ArrayList方法的代码,不过与源码可能会略有区别,但是思想都是一样的,影响不大。由于是自定义实现ArrayList,所以给这个类起名为MyArrayList,这个类是一个泛型类🔍

1.ArrayList的成员属性

我们已经知道了ArrayList底层是一个动态数组,那么不用多说,成员属性当然要有一个数组,还要有一个记录当前数组存储了几个数据的变量,以及一个常量。

public class MyArrayList<E> {
	 //在声明MyArrayList时,如不指明大小,则初始大小为10
    private static final int STAR_SIZE = 10;
    private E[] arrays;
    private int size = 0;

2.ArrayList的成员方法

最基本的方法也是必不可少的方法当然是构造方法🔍咯。

//两种构造函数,允许用户创建指定大小或者默认大小的线性表
    public MyArrayList(){
        init(STAR_SIZE);
    }
    public MyArrayList(int initCapacity){
        init(initCapacity);
    }
    //私有化方法init帮助构造函数来初始化数组arrays
    private void init(int capacity){
        //注意不能建立泛型数组,因此我们强行转换一个Object数组🔍
        contents = (E[]) new Object[capacity];
    }

获得元素个数和判断是否有元素

public int size(){
        return this.size;
    }
    public boolean isEmpty(){
        return size()==0;
    }

清空数组
数组存的都是引用数据类型🔍,只要将所有引用指向null,GC🔍会帮你把这些数据内存回收哒。

 public void clear(){
        for(int i=0;i<this.size;i++){
            //将数组中元素的引用指向null,这样GC就可以回收内存
            arrays[i] = null;
        }
        this.size = 0;
    }

增加数据
默认在数组最后添加数据,逻辑很简单,主要是要判断数组是否已经满了,满了的话就扩容咯。

public boolean add(E element){
        if(size()>=arrays.length){
            //一旦列表中的元素个数等于了数组的长度,我们就对数组进行扩容
            ensureCapacity();
        }
        //将元素放置最后位置并把元素数目加1
        arrays[size++] = element;
        return true;
    }

在指定位置增加数据
增加数据的原理就是先将这个位置开始的数据整体往后移,把这个位置空出来,然后添加数据即可。需要注意的是,我们需要判断这个数组是否满了,以及输入的位置是否合法。

public void add(int index, E element){
        //一旦index不合法就抛出异常
        //此处允许index等于size,相当于尾插
    	if(index<0 || index>size()){
			//这里我就不自定义一个异常类了,用输出代替
			System.out.println("位置不合法,请检查");
			return;
		}
    	if(size()>=arrays.length){
			ensureCapacity();
		}
        //将数据后移
        for(int i=size();i>index;i--)
            arrays[i] = arrays[i-1];
        //插入元素
        arrays[index] = element;
        this.size++;
    }

扩容数组
动态数组嘛,最大的好处就是这个数组的大小不是固定的,不够了就可以再扩大嘛。不过嘞,这里值得一提的是,它有一个缺点就是可能会有空间浪费,就比说现在数组大小为100,你有101个数据要储存,那你就要将数组扩容到200(假设数组扩容时扩大两倍),那么剩下的99个数组空间就浪费掉了。

    private void ensureCapacity(){
        //扩容多少可以自己定
        E[] newArrays = (E[]) new Object[2*arrays.length+1];
        //然后将数据拷贝到新数组中去
        System.arraycopy(arrays,0,newArrays,0,size());
        //在让arrays指向新的数组
        arrays = newArrays;
    }

注:为了有些还没学习到泛型概念的友友们,下面的方法将不会用到泛型,方便理解。
删除数据
这个原理很简单,就是找到这个数据的位置,然后将后面的数据整体往前移动就好,然后修改size变量的大小即可。

	//删除第一次出现的关键字key
    public void remove(int key) {
        for (int i = 0; i < this.size; i++) {
            if(key == this.arrays[i]){
                for (int j = i; j < this.size-2; j++) {
                    this.arrays[i] = this.arrays[i+1];
                }
                this.size--;
                return;
            }
        }
    }

查找数据
这不用多说啦,就是数组下标查找嘛,最重要的还是判断输入的位置是否合法,比如小于零呀,大于等于size呀。

    // 获取 pos 位置的元素
    public int get(int pos) {
        if(!checkPosIndex(pos)){
            System.out.println("位置不合法,请检查");
            return -1;
        }
        return this.arrays[pos];
    }
        private boolean checkPosIndex(int pos) {
        if(pos < 0 || pos >= this.size){
            return false;
        }
        return true;//合法
    }

修改数据
这个跟查找数据思路差不多,关键还是判断位置是否合法。

    // 给 pos 位置的元素设为【更新为】 value
    public void set(int pos, int value) {
        if(!checkPosIndex(pos)){
            System.out.println("位置不合法,请检查");
            return;
        }
        this.arrays[pos] = value;
    }

ArrayList最基本要实现的功能就是增、删、查、改,当然并不代表只有这些方法,还有许多功能这里就不多赘述。

三.ArrayList的使用方法

要使用Arraylist其实很简单,我们明白了底层实现原理之后,使用起来那肯定是一个得心应手啦,毕竟不就是个语法规范的问题嘛,跟之前实例化对象然后调用方法一个意思,无非多了个泛型的概念咯,虽然泛型语法还是挺难的,但使用它还是不成问题对吧,easy啦。
在这里插入图片描述
下面就以最基本的增、删、查、改为例来进行讲解,来咯
增加数据
添加元素使用 add() 方法,add()方法进行了重载🔍,可以通过传不同的参数来实现不同的功能,下面只介绍最简单的。

package Demo;
import java.util.ArrayList;
 
public class DemoArraylistEach {
    public static void main(String[] args) {
    //<>金括号里输入你要传的参数类型🔍,list就是变量名,等号右边new一个对象
        ArrayList<String> list = new ArrayList();
        //调用add方法,为其注入你喜爱的元素吧
        list.add("蓝色妖姬");
        list.add("两年半");
        list.add("十三年");
        //这个以字符串的形式输出list,也可以通过遍历的方法来输出list的每个元素
        System.out.println(list);
    }
}

输出结果:

[蓝色妖姬, 两年半, 十三年]

删除数据
删除元素使用 remove() 方法,remove()方法同样也进行了重载🔍,下面也只介绍最简单的。

import java.util.ArrayList;
 
public class RunoobTest {
    public static void main(String[] args) {
        ArrayList<String> sites = new ArrayList<String>();
        sites.add("黄");
        sites.add("鹿");
        sites.add("吴");
        sites.add("张");
        sites.remove(3); // 删除第四个元素
        System.out.println(sites);
    }
}

输出结果:

[黄, 鹿, 张]

ArrayList其他常用方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
相信各位大宝贝们通过上面两个例子可以很容易就举一反三,使用这些方法啦。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值