Java数据结构——ArrayList

[复制链接]
发表于 2025-9-22 23:25:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
媒介
ArrayList是一种序次表,⽤⼀段物理地点连续的存储单元依次存储数据的线性结构,一般情况都是采取数组存储,在数组上实现一些增删查改等等功能, ArrayList是Java中最常用的动态数组实现之一,其内部的内存空间是可以改变的,本日就来探究一下ArrayList使用及其原理

一 ArrayList的简介

ArrayList固然是一个寻常的类,但是它实现了List接口
List接口在JDK17的部分源码

ArrayList类在JDK17的部分源码

我们可以从上面看出
  1. 1. List是一个接口,继承了Collection类
  2. 2. ArrayList是一个类,继承了AbstractList类
  3. 3. ArrayList实现了List中的RandomAccess接口,说明其支持随机访问
  4. 4. 实现了Cloneable接口,说明其支持clone
  5. 5. 实现了Serializable接口,说明其支持序列化
复制代码
下面是ArrayList的一些常用方法,因为实在现了List接口,以是List中的抽象方法,在ArrayList都有

二 ArrayList的构造方法

ArrayList ()无参构造ArrayList (int initialCapacity)确定初始容量ArrayList (Collection<? extends E> c)使用其他Collection来构造
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         //1.无参构造
  4.         List<Integer> list = new ArrayList<>();
  5.         //2.含参构造,确定其初始化的容量,确定其初始化容量为1
  6.         List<Integer> list1 = new ArrayList<>(1);
  7.         //3.利用其他构造
  8.         //这里list2与list的元素一致
  9.         List<Integer> list2 = new ArrayList<>(list);
  10.     }
  11. }
复制代码
无参构造源码


固然无参构造没有给定容量,但是编译器会默认一个容量,JDK17中默认容量为10
含初始容量一个参数的构造

如果给定初始容量,编译器会举行判断,如果初始容量>0就按照你给定的容量创建对象,如果初始容量==0就按照默认的容量举行创建,反之如果<0就抛出容量不合法的非常
留意在创建线性表的时候,要指定是什么范例的线性表
1.如果不写范例,编译器会报错,因为其不知道是什么范例

2.而且其必须是包装范例
如果写成寻常范例编译器也会报错

3.那何为包装范例呢
根本数据范例包装类byteByteshortShortintIntegerlongLongfloatFloatdoubleDoublecharCharacterbooleanBoolean这些范例中除了int和char的包装类有所改变,其他的都是根本范例的首字母大写
三 ArrayList常用方法

方法表明boolean add(E e)尾插 evoid add(int index, E e)将 e插入到 index 位置boolean addAll(Collection<? extends E> c)尾插 c 中的全部元素E remove(int index)删除 index 下标元素boolean remove(Object o)删除碰到的第一个 oE get(int index)获取下标 index 下标元素E set(int index, E e)将下标 index 下标元素设置为 evoid clear()清空列表boolean contains(Object o)判断 o 是否在线性表中int indexOf(Object o)返回第一个 o 地点下标int lastIndexOf(Object o)返回末了一个 o 的下标List subList(int fromIndex, int toIndex)截取部分 listint size()返回此列表中的实际的元素数1.add()方法

   boolean add(E e)
将指定的元素追加到此列表的末端。
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         System.out.println(list);
  8.     }
  9. }
复制代码
运行结果如下

留意这里的如果已经确定了是那种包装范例,就不可以在添加其他的包装范例的数据了

  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>(3);
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         System.out.println("扩容前长度"+list.size());
  8.         list.add(4);
  9.         System.out.println("扩容后长度"+list.size());
  10.         System.out.println(list);
  11.     }
  12. }
复制代码
运行结果如下

我们发现一个题目就是上面我们初始化容量为3,但是我们添加了4个元素其并没有报错,为什么呢?那是因为其ArrayList类add方法中有扩容操作,但是这里的真实长度变为4

   void add(int index, E e)
在index下标插入e
index>=0&&index<=其列表的长度
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         //在1下标插入99
  8.         list.add(1,99);
  9.        // list.add(4,1);
  10.         System.out.println(list);
  11.     }
  12. }
复制代码
我们要留意这里并不是简单更换,而是将某一个下标修改为一个数后,本来的数要以后偏移
偏移的同时其如果存储不下,也会举行扩容
运行结果如下

留意这里的下标要合法 index下标>=0&&index<=list.size()
这里即是其list的容量也可以,因为如许正好就相称于上面一个参数的add举行尾插

如果大于list.size()就会出现数组越界非常
这里长度为3,这里index>=0&&index<=3,因此这里出现数组越界非常非常了

   boolean addAll(Collection<? extends E> c)
将指定集合中的全部元素追加到此列表的末端
这里是可以本身尾插本身的
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         System.out.println("尾插前list"+list);
  8.         List<Integer> list1 = new ArrayList<>();
  9.         list1.add(10);
  10.         list1.add(20);
  11.         list1.add(30);
  12.         //将list1尾插到list后面
  13.         list.addAll(list1);
  14.         System.out.println("尾插后list"+list);
  15.     }
  16. }
复制代码

这里实在也是可以本身尾插本身的
下面这个本身尾插本身乐成了

留意这里是不可以差别范例的列表举行尾插
一个列表中不可以放两种包装范例一样,尾插差别范例的肯定会报错

2.remove()方法

   E remove(int index)
删除 index 下标元素
index>=0&&index<列表长度
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         //删除1下标的值
  8.         list.remove(1);
  9.         System.out.println(list);
  10.     }
  11. }
复制代码
这里删除1下标的值,也就是删除这里的2
运行结果如下

   boolean remove(Object o)
删除碰到的第一个 o
在使用的时候要将一个数装箱以后再举行删除
  这里直接使用根本范例就是删除的是对应下标的值,而不是本身想要的

这时候就要举行装箱操作,如许就可以删除对应的值了,删除的就不是下标对应的值了
这里就是删除第一个出现的1元素,而不是下标,以是这里0下标的1被删除了

   void clear()
清空列表
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         //删除1下标的值
  8.         Integer a = 1;
  9.         list.remove(a);
  10.         System.out.println(list);
  11.         list.clear();
  12.         System.out.println("清空后"+list);
  13.     }
  14. }
复制代码
这里就是将其置为空

3.get()和set()方法

   E get(int index)
获取下标 index 下标元素
  E set(int index, E e)
将下标 index 下标元素设置为 e
index>=0&&index<列表长度
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         System.out.println("获取1下标的值:"+list.get(1));
  8.         list.set(1,999);
  9.         System.out.println("修改后1下标的值:"+list.get(1));
  10.     }
  11. }
复制代码
这里和add方法差别的是,这个是直接修改值,而add是添加值
运行结果如下

4.index()方法

   int indexOf(Object o) 返回第一个 o 地点下标
int lastIndexOf(Object o) 返回末了一个 o 的下标
找不到就返回-1
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         list.add(1);
  8.         System.out.println("第一个元素1的下标:"+list.indexOf(1));//0
  9.         //如果没有找到就返回-1
  10.         System.out.println(list.indexOf(100));//-1
  11.         System.out.println("最后一个元素1的下标:"+list.lastIndexOf(1));
  12.     }
  13. }
复制代码

5.subList截取方法

   List subList(int fromIndex, int toIndex)
截取下标[fromIndex,toIndex]的list
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         list.add(4);
  8.         list.add(5);
  9.         List<Integer> list1 = list.subList(1,3);
  10.         //这里是左闭右开的截取方法
  11.         System.out.println("截取[1,3)下标的元素:"+list1);
  12.     }
  13. }
复制代码
运行结果如下

实在这里并不是真正的截取
比方:
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         list.add(4);
  8.         list.add(5);
  9.         List<Integer> list1 = list.subList(1,3);
  10.         //这里是左闭右开的截取方法
  11.         System.out.println("截取[1,3)下标的元素:"+list1);
  12.         list1.remove(0);//删除list1中的0下标的值也就是2
  13.         System.out.println("被截取的list: "+ list);
  14.     }
  15. }
复制代码
这里删除截取中0下标的2,而本来的list中的2也被删除了
运行结果如下

可以看出这里我们对截取的内容删除,导致了list中的这部分内容也被删除了

只是将其一个对象指向截取的部分,只是将其截取部分的地点放入一个新对象中,因此对截取修改也会影响本来的list
四 ArrayList的遍历

for循环遍历

  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         list.add(4);
  8.         list.add(5);
  9.         for (int i = 0; i < list.size(); i++) {
  10.             //获取下标对应的值
  11.             System.out.print(list.get(i)+" ");
  12.         }
  13.     }
  14. }
复制代码
这里的size()获取其列表长度
举行一个一个下标遍历就行
运行结果如下

增强for循环(for each)

  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         list.add(4);
  8.         list.add(5);
  9.         //每个元素的类型为Integer
  10.         for (Integer integer:list) {
  11.             System.out.print(integer+" ");
  12.         }
  13.     }
  14. }
复制代码
这里使用for-each遍历,这里列表中元素范例都为Integer,就用一个暂时integer来访问和打印

迭代器遍历

  1. public class Test {
  2.     public static void main(String[] args) {
  3.         List<Integer> list = new ArrayList<>();
  4.         list.add(1);
  5.         list.add(2);
  6.         list.add(3);
  7.         list.add(4);
  8.         list.add(5);
  9.         //使用迭代器
  10.         //从前向后遍历
  11.         Iterator<Integer> it = list.iterator();
  12.         //获取其开始位置
  13.         while(it.hasNext()){
  14.             //不断的往后走
  15.             System.out.print(it.next()+" ");
  16.         }
  17.         System.out.println();
  18.         //从后向前遍历
  19.         ////给定其下标从其最后面开始
  20.         ListIterator<Integer> it1 = list.listIterator(list.size());
  21.         while (it1.hasPrevious()){
  22.             System.out.print(it1.previous()+" ");
  23.         }
  24.         System.out.println();
  25.     }
  26. }
复制代码
运行结果如下

ArrayList题目及其思索

  1. 1.在其查找数据是非常简单和高效的
  2. 2.但是,ArrayList列表在添加或者删除元素的时候,都需要将其后面的数据向前移动,时间复杂度为O(N)
  3. 3.在添加数据时候可能会扩容,是1.5倍数扩容,有点浪费空间
复制代码
因此还必要其他的数据结构来完成添加大概删除元素会更高效一点
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表