👽 博客主页:<芝士盘盘>
❤️🔥💗💓一键三连:👍 点赞 ✌️ 收藏 👌 关注
👻小小勉励:当一个人的心专注在一桩事情上的时候,这种热情是意义深重的。——马克吐温
一.何为ArrayList
用官方的话来说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其他常用方法
相信各位大宝贝们通过上面两个例子可以很容易就举一反三,使用这些方法啦。