ArrayList常用方法及手撕源码

初识ArrayList

一、简介:

ArrayList是 java 集合框架中比较常用的数据结构了。继承自 AbstractList,实现了 List 接口。底层基于数组实现容量大小动态变化。允许 null 的存在。同时还实现了 RandomAccess、Cloneable、Serializable 接口,所以ArrayList 是支持快速访问、复制、序列化的。

ArrayList底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素

二、常用方法:

add:添加元素

ArrayList<String> list = new ArrayList<>();

list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");

System.out.println(list);

输出结果:

image-20220511203829829

add(int index, String element):在此列表中的指定位置插入指定的元素。

//在此列表中的指定位置插入指定的元素。
list.add(2, "钱七");//在下标为2的位置添加元素
image-20220511204152815

addAll(Collection<? extends E> c):按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。

//按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
ArrayList<String> newList = new ArrayList<>();
Collections.addAll(newList, "孙悟空", "猪八戒", "沙和尚");
list.addAll(newList);

输出结果为:

image-20220511204656760

addAll(int index, Collection<? extends E> c):将指定集合中的所有元素插入到此列表中,从指定的位置开始。

ArrayList<String> newList2 = new ArrayList<>();
Collections.addAll(newList2, "如来", "唐僧", "观音");
list.addAll(2, newList2);//在下标为2的位置插入newList2集合

输出结果:

image-20220511205058292

remove:删除该列表中指定位置的元素。

list.remove("钱七");//删除元素为"钱七"的元素
image-20220511205424084
list.remove(6);//删除指定下标的元素
image-20220511205600459

//从此列表中删除指定集合中包含的所有元素。

list.removeAll(newList2);
image-20220512172619591

retainAll:仅保留此列表中包含在指定集合中的元素。

list.retainAll(newList1);

set:用指定的元素替换此列表中指定位置的元素。

list.set(1, "马保国");
image-20220512173041383

size():返回此列表中的元素数。

System.out.println("size = " + list.size());

toArray():以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。

Object[] array = list.toArray();
System.out.println(Arrays.toString(array));

三、手撕ArrayList的底层结构

ArrayList的底层结构是一个Object类型的一维数组,继承了AbstractList类,并且实现了List接口, RandomAccess接口和 Cloneable接口。

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

   //默认初始容量。
   private static final int DEFAULT_CAPACITY = 10;
   //没有元素的空数组(长度为0)
   private static final Object[] EMPTY_ELEMENTDATA = {};
   //空内容的数组(长度为0)
   private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
   //容器(ArrayList集合中所有的元素都是存在这个一维数组里的)
   transient Object[] elementData;//new Object[10]   
   //元素个数(指针)
   private int size;
   //数组最大容量
   private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
   //最大容量之所以是Integer的最大值-8,是因为ArrayList的底层就是一个以为数组,一维数组存储在堆内存中,会占用一定的内存空间,比如我们的头部信息,包括了其中的内存地址以及数组长度,数据类型等信息

   //ArrayList的无参构造
   public ArrayList() {
       //构造一个初始容量为10的空列表。
       this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
   }

   //ArrayList的有参构造
   public ArrayList(int initialCapacity) { //验证初始化容量的合法性
       if (initialCapacity > 0) {
           this.elementData = new Object[initialCapacity];
       } else if (initialCapacity == 0) {
           this.elementData = EMPTY_ELEMENTDATA;
       } else {
           throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
       }
   }

   public boolean add(E e) {
       ensureCapacityInternal(size + 1);  
       elementData[size++] = e;
       return true;
   }

  //使用无参构造创建对象时,第一次添加元素就会进入的判断
   private void ensureCapacityInternal(int minCapacity) {
       if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
           minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//minCapacity = 10
       }

       ensureExplicitCapacity(minCapacity);
   }

   private void ensureExplicitCapacity(int minCapacity) {
       modCount++;

       //有溢出意识的代码 -- 判断是否可以扩容(要扩容的长度必须大于原数组的长度)
       if (minCapacity - elementData.length > 0)
           grow(minCapacity);
   }

   private void grow(int minCapacity) {
       // 有溢出意识的代码 -- 计算扩容的容量
       int oldCapacity = elementData.length;
       int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容机制为原数组长度的1.5倍
       if (newCapacity - minCapacity < 0)
           newCapacity = minCapacity;
       if (newCapacity - MAX_ARRAY_SIZE > 0)
           newCapacity = hugeCapacity(minCapacity);
       elementData = Arrays.copyOf(elementData, newCapacity);
   }
   
   private static int hugeCapacity(int minCapacity) {
       if (minCapacity < 0)
           throw new OutOfMemoryError();
       return (minCapacity > MAX_ARRAY_SIZE) ?
           Integer.MAX_VALUE :
           MAX_ARRAY_SIZE;
   }



}  
public static void main(String[] args) {

   ArrayList<String> list = new ArrayList<>();
   list.add("张三");
   list.add("李四");

总结:

  • ArrayList的底层是Object类型的一位数组
  • 在使用无参构造的时候,ArrayList会将数组赋值成没有长度的空数组
  • 在使用有参构造的时候,如果参数大于0,则创建参数长度的数组,如果参数等于0会将数组赋值成没有长度的空数组,如果参数小于0就会报错
  • ArrayList的底层有个变量规定初始化容量为10(DEFAULT_CAPACITY = 10),如果使用无参构造创建ArrayList对象,第一次添加元素的时候,会将底层的Object类型的一维数组初始化为10长度的数组
  • ArrayList的扩容机制是1.5倍(int newCapacity = oldCapacity + (oldCapacity >> 1))
  • ArrayList的最大容量为:Integer.MAX_VALUE-8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值