ArrayList 总结:核心特性、常用接口、代码实现
本文聚焦 Java 集合框架中的ArrayList,从它的定义与核心特性出发,系统梳理所有常用接口的作用与返回值,最后给出整体总结。适合作为学习笔记或面试速查。
目录
- 一、ArrayList 简介
- 二、ArrayList 的构造方式
- 三、ArrayList 常用接口(作用 + 返回值)
- 四、接口使用示例
- 五、模拟实现代码
- 六、总结
一、ArrayList 简介
在集合框架中,ArrayList 是一个普通的类,实现了 List 接口,它的本质是一个动态类型的顺序表。
| 特性 | 说明 |
|---|---|
| 泛型实现 | 以泛型方式实现,使用时必须先实例化,如ArrayList<Integer> |
| RandomAccess | 实现了该接口,表明 ArrayList支持随机访问(下标访问 O(1)) |
| Cloneable | 实现了该接口,表明 ArrayList可以 clone |
| Serializable | 实现了该接口,表明 ArrayList支持序列化 |
| 非线程安全 | 与 Vector 不同,ArrayList不是线程安全的;单线程下使用,多线程中可选择Vector或CopyOnWriteArrayList |
| 动态扩容 | 底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表 |
一句话记忆:ArrayList =泛型 + 随机访问 + 可克隆 + 可序列化 + 非线程安全 + 动态扩容的动态顺序表。
底层结构:
elementData:真正的Object[]数组,物理地址连续;size:有效元素个数(≠ 数组容量,前者是「装了多少」,后者是「最多能装多少」)。
二、ArrayList 的构造方式
publicstaticvoidmain(String[]args){// 构造一个空的列表List<Integer>list1=newArrayList<>();// 构造一个具有 10 个容量的列表List<Integer>list2=newArrayList<>(10);// 拷贝构造:构造好之后,与源集合中的元素一致ArrayList<Integer>list3=newArrayList<>(list2);// ⚠️ 避免省略类型,否则任意类型都能存放,使用时将是一场灾难Listlist4=newArrayList();list4.add("111");list4.add(100);}| 构造方法 | 作用 |
|---|---|
ArrayList() | 构造一个空的列表,首次添加元素时才分配容量(10) |
ArrayList(int initialCapacity) | 构造一个具有指定初始容量的列表,可减少扩容次数 |
ArrayList(Collection<? extends E> c) | 拷贝构造,元素与源集合一致 |
建议:始终显式指定泛型,否则编译期类型检查失效,运行时容易出现类型混乱。
三、ArrayList 常用接口(作用 + 返回值)
以下为 ArrayList / List 最常用的接口,逐一给出方法签名、作用、返回值。
| 方法 | 作用 | 返回值 |
|---|---|---|
boolean add(E e) | 在列表末尾添加元素 | 添加成功返回true |
void add(int index, E e) | 在index位置插入元素,index 及后续元素统一后移一位 | 无返回值 |
E remove(int index) | 删除index位置的元素,该元素之后的元素统一前移一位 | 返回被删除的元素 |
boolean remove(Object o) | 删除第一次出现的指定元素 | 删除成功返回true,元素不存在返回false |
E get(int index) | 获取index位置的元素(index 必须 ∈ [0, size)) | 返回该位置的元素 |
E set(int index, E e) | 将index位置的元素设为e | 返回被替换的旧元素 |
boolean contains(Object o) | 判断列表中是否包含指定元素 | 包含返回true,否则返回false |
int indexOf(Object o) | 查找指定元素第一次出现的位置(从前往后找) | 找到返回下标,未找到返回 -1 |
int lastIndexOf(Object o) | 查找指定元素最后一次出现的位置(从后往前找) | 找到返回下标,未找到返回 -1 |
int size() | 获取列表中有效元素个数 | 返回 size(注意:不是底层数组容量) |
void clear() | 清空列表 | 无返回值 |
boolean isEmpty() | 判断列表是否为空 | 为空返回true,否则返回false |
List<E> subList(int fromIndex, int toIndex) | 截取[fromIndex, toIndex)区间,与原列表共用同一个 elementData 数组 | 返回一个 SubList视图(非独立副本) |
Object[] toArray() | 将列表转换为数组 | 返回Object[]数组 |
Iterator<E> iterator() | 获取迭代器 | 返回Iterator<E>对象 |
ListIterator<E> listIterator() | 获取列表迭代器(支持双向遍历) | 返回ListIterator<E>对象 |
⚠️两个极易踩坑的返回值:
remove(int index)返回被删除的元素,而remove(Object o)返回boolean—— 两个重载方法语义完全不同;subList()返回的是原列表的片段视图(View),与原文 list共享同一个底层数组(同一地址),修改视图会影响原列表。
四、接口使用示例
下面通过一段完整的代码,演示上述常用接口的实际用法。代码中每一步都配有注释,方便对照理解。
publicstaticvoidmain(String[]args){// 1. 构造一个空的列表List<String>list=newArrayList<>();System.out.println("初始列表:"+list+",是否为空:"+list.isEmpty());// 2. 在列表末尾依次添加元素list.add("JavaSE");list.add("JavaWeb");list.add("JavaEE");list.add("JVM");list.add("测试课程");System.out.println("添加元素后:"+list);// 3. 获取 list 中有效元素个数(注意:不是底层数组容量)System.out.println("有效元素个数 size = "+list.size());// 4. 获取和设置 index 位置上的元素,注意 index 必须介于 [0, size) 间System.out.println("get(1) = "+list.get(1));list.set(1,"JavaWEB");// 把下标 1 的元素替换为 "JavaWEB"System.out.println("set 之后 get(1) = "+list.get(1));// 5. 在 list 的 index 位置插入指定元素,index 及后续元素统一往后搬移一个位置list.add(1,"Java数据结构");System.out.println("在下标 1 插入后:"+list);// 6. 删除指定元素(按值删除),找到了就删除,该元素之后的元素统一往前搬移一个位置list.remove("JVM");System.out.println("删除 JVM 后:"+list);// 7. 删除 index 位置上的元素(按下标删除),注意 index 不要超过有效元素个数,否则抛下标越界异常list.remove(list.size()-1);System.out.println("删除最后一个元素后:"+list);// 8. 检测是否包含指定元素,包含返回 true,否则返回 falseif(list.contains("测试课程")){list.add("测试课程");System.out.println("包含测试课程,已再次添加:"+list);}// 9. 查找指定元素第一次出现的位置:indexOf 从前往后找,lastIndexOf 从后往前找list.add("JavaSE");System.out.println("indexOf(JavaSE) = "+list.indexOf("JavaSE"));System.out.println("lastIndexOf(JavaSE) = "+list.lastIndexOf("JavaSE"));// 10. 使 list 中 [0, 4) 之间的元素构成一个新的 SubList 返回,但和 ArrayList 共用同一个 elementData 数组List<String>ret=list.subList(0,4);System.out.println("subList(0,4) = "+ret);// 11. 清空列表list.clear();System.out.println("清空后 size = "+list.size()+",是否为空:"+list.isEmpty());}运行结果说明:
isEmpty()在列表刚创建时返回true,添加元素后返回false;set(1, "JavaWEB")会返回被替换的旧元素(此处为"JavaWeb"),但示例中未打印,读者可自行验证;add(1, "Java数据结构")会把原下标 1 及之后的元素整体后移一位;remove("JVM")按值删除,删除成功后返回true;remove(list.size() - 1)按下标删除最后一个元素,并返回被删除的元素;subList(0, 4)返回的是视图,修改ret会同步影响原list,反之亦然。
💡动手练习:试着在
subList返回的ret上调用set(0, "修改"),再打印原list,观察两者是否同步变化,从而加深对「视图共享底层数组」的理解。
五、模拟实现代码
packagemyarraylist;publicclassMyArrayList{//用String来实现privateString[]data=null;privateintsize=0;publicMyArrayList(){data=newString[10];}publicMyArrayList(intcapacity){if(capacity<10){capacity=10;}data=newString[capacity];size=capacity;}privatevoidresize(){String[]newString=newString[data.length+(data.length>>1)];for(inti=0;i<size;i++){newString[i]=data[i];}data=newString;}publicvoidadd(intindex,Stringvalue){if(index<0||index>size){thrownewIndexOutOfBoundsException();}if(size==data.length){resize();}for(inti=size-1;i>=index;i--){data[i+1]=data[i];}data[index]=value;size++;}publicvoidadd(Stringelem){if(size>=data.length){resize();}data[size]=elem;size+=1;}publicStringremove(intindex){if(index<0||index>size){thrownewIndexOutOfBoundsException();}Stringelem=data[index];for(inti=index+1;i<size;i++){data[i-1]=data[i];}size--;returnelem;}publicBooleanremove(Stringelem){for(inti=0;i<size;i++){if(data[i].equals(elem)){remove(i);//因为这里复用的是上一个删除 上一个删除已经减减所以这里不用渐渐就行returntrue;}}returnfalse;}publicStringget(intindex){if(index<0||index>size){thrownewIndexOutOfBoundsException();}returndata[index];}publicvoidset(intindex,Stringelem){if(index<0||index>size){thrownewIndexOutOfBoundsException();}data[index]=elem;}publicvoidclear(){size=0;}publicbooleancontains(Stringelem){for(inti=0;i<size;i++){if(data[i].equals(elem)){returntrue;}}returnfalse;}publicintindexOf(Stringelem){for(inti=0;i<size;i++){if(data[i].equals(elem)){returni;}}return-1;}publicintlastIndexOf(Stringelem){for(inti=size-1;i>=0;i--){if(data[i].equals(elem)){returni;}}return-1;}publicMyArrayListsubList(intfromIndex,inttoIndex){if(fromIndex<0||toIndex>0){thrownewIndexOutOfBoundsException();}MyArrayListlist=newMyArrayList(toIndex-fromIndex);for(inti=fromIndex;i<toIndex;i++){list.add(data[i]);}returnlist;}@OverridepublicStringtoString(){StringBuilderstr=newStringBuilder();str.append("[");for(inti=0;i<size;i++){str.append(data[i]);if(i==size-1){break;}str.append(", ");}str.append("]");returnstr.toString();}publicstaticvoidmain(String[]args){MyArrayListlist=newMyArrayList();list.add("A");list.add("B");list.add("C");list.add(2,"g");list.remove(2);list.remove("A");System.out.println(list);}}六、总结
- ArrayList 本质:Java 集合框架中实现的动态顺序表,底层是一段可动态扩容的连续空间;
- 核心特性:泛型实现、支持随机访问、可 clone、可序列化、非线程安全;
- 关键接口:
add/remove/get/set/contains/indexOf/lastIndexOf/size/clear/subList等,需牢记各自作用与返回值; - 易错点:
remove(int index)返回被删除元素,remove(Object o)返回 boolean;subList()返回的是共享底层数组的视图,并非独立副本;size()返回的是有效元素个数,不是底层数组容量;
- 使用建议:已知数据量时预先指定初始容量,以减少扩容带来的开销。
如果这篇文章对你有帮助,欢迎点赞 👍 + 收藏 ⭐ + 关注,后续会继续更新 Java 集合框架系列文章!