当前位置: 首页 > 后端技术 > Java

甚至有人说ArrayList大了2倍,今天带大家撕ArrayList的源码

时间:2023-04-01 20:53:27 Java

ArrayList是我们开发中最常用的集合,但是很多人不知道它的源码,所以在面试的时候,面试官问到是不可能的回答一个有点深入的问题。今天我们就一起来探究ArrayList的源码。1.简介ArrayList底层是一个数组,它允许有null元素,并且可以动态扩展。size、isEmpty、get、set、add等方法时间复杂度为O(1)非线程安全,并发修改时会抛出ConcurrentModificationException。2.初始化//初始容量privatestaticfinalintDEFAULT_CAPACITY=10;//空数组privatestaticfinalObject[]EMPTY_ELEMENTDATA={};//默认空数组privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};//arraytransient用于存储元素Object[]elementData;//无参数初始化,默认为空数组>0){this.elementData=newObject[initialCapacity];}elseif(initialCapacity==0){this.elementData=EMPTY_ELEMENTDATA;}else{thrownewIllegalArgumentException("非法容量:"+initialCapacity);}}记住:没有参数初始化的时候,默认是一个空数组,没有初始化容量的大小。首次添加元素时会初始化容量。3.添加元素publicbooleanadd(Ee){//保证数组容量足够,size为元素个数ensureCapacityInternal(size+1);//直接赋值elementData[size++]=e;returntrue;}//确保数组容量足够){//如果数组等于空数组,则最小容量为10if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){returnMath.max(DEFAULT_CAPACITY,minCapacity);}returnminCapacity;}privatevoidensureExplicitCapacity(intminCapacity){modCount++;//如果需要的最小容量大于数组长度,就展开if(minCapacity-elementData.length>0)grow(minCapacity);}看看展开逻辑://要展开,复制旧的数据到新数组privatevoidgrow(intminCapacity){intoldCapacity=elementData.长度;//oldCapacity>>1是oldCapacity除以2,也就是1.5倍的扩展intnewCapacity=oldCapacity+(oldCapacity>>1);//如果扩展容量小于最小容量,则扩展容量等于最小容量if(newCapacity-minCapacity<0)newCapacity=minCapacity;//如果扩展容量大于Integer的最大值,则使用Integer的最大值if(newCapacity-MAX_ARRAY_SIZE>0)newCapacity=hugeCapacity(minCapacity);//扩容赋值给原数组elementData=Arrays.copyOf(elementData,newCapacity);}可以看到扩容是原来容量的1.5倍,不是翻倍。最大容量是Integer的最大值。添加元素时,没有元素验证,可以为null再看数组复制的逻辑,这里是Arrays类中的方法:/***@paramoriginal原始数组*@paramnewLength新容量大小*/publicstaticT[]copyOf(T[]original,intnewLength){return(T[])copyOf(original,newLength,original.getClass());}publicstaticT[]copyOf(U[]original,intnewLength,ClassnewType){//创建一个具有新容量的新数组T[]copy=((Object)newType==(Object)Object[].班级)?(T[])新对象[newLength]:(T[])Array.newInstance(newType.getComponentType(),newLength);//将原数组的元素复制到新数组中System.arraycopy(original,0,copy,0,Math.min(original.length,newLength));returncopy;}最后调用System类的数组copy方法,是一个native方法:目标数组的起始位置*@paramlength复制的长度*/publicstaticnativevoidarraycopy(Objectsrc,intsrcPos,Objectdest,intdestPos,intlength);4.删除单个元素publicbooleanremove(Objecto){//判断要删除的元素是否为nullif(o==null){//遍历数组for(intindex=0;index0)//从index+1开始复制,即后面的元素向左移动一个位置System.arraycopy(elementData,index+1,elementData,index,numMoved);//给数组最后一个元素赋null,防止内存泄露elementData[--size]=null;}要知道,删除元素,就是遍历数组,循环比较是否等于目标值,如果等于,将该位置后面的元素整体向左移动,然后将数组的最后一个元素赋值为null。5.批量删除//批量删除ArrayList和集合中都存在的元素cpublicbooleanremoveAll(Collectionc){//非空校验Objects.requireNonNull(c);//批量删除returnbatchRemove(c,false);}privatebooleanbatchRemove(Collectionc,booleancomplement){finalObject[]elementData=this.elementData;整数r=0,w=0;布尔修改=假;try{for(;r