概述(一)ArrayList是一个基于定长数组实现的变长集合类。(2)ArrayList允许空值和重复元素。添加元素时,扩展机制会生成一个更大的数组。(3)随机查找操作可以保证在O(1)复杂度下完成。(4)ArrayList是一个非线程安全的类。为了追求效率,ArrayList没有实现同步(synchronized)。如果多个线程需要并发访问,用户可以手动同步或者使用Vector代替。类的属性/***默认初始容量*/privatestaticfinalintDEFAULT_CAPACITY=10;/***空实例的共享空数组实例*/privatestaticfinalObject[]EMPTY_ELEMENTDATA={};/***ArrayList一个实际数据存储的数组*一个数组缓冲区,存储ArrayList的元素。ArrayList的容量就是这个数组缓冲区的长度。*任何带有elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList在添加第一个元素时将扩展为DEFAULT_CAPACITY。Object[]数组,也就是说该数组可以容纳任何对象(所有对象都继承自父类Object)*/transientObject[]elementData;/***共享空数组实例,用于默认大小的空实例*/privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};/***elementData的大小,size是逻辑长度,不是数组长度。*/privateintsize;//很有意思,下面介绍protectedtransientintmodCount=0;static修饰的变量,常驻在方法区,我们不需要new,JVM会提前帮我们初始化,这个特性在实际开发过程中,经常被用作缓存。ArrayListnew时,考虑缓存。为了防止我们重复创建无用数组,所有newArrayList底层数组都指向缓存在方法区的Object[]数组。构造方法//参数为初始容量publicArrayList(intinitialCapacity){//判断容量的合法性if(initialCapacity>0){//elementData为实际存放元素的数组this.elementData=newObject[initialCapacity];}elseif(initialCapacity==0){//如果传入的长度为0,则直接使用自己定义的成员变量(空数组)this.elementData=EMPTY_ELEMENTDATA;}else{thrownewIllegalArgumentException("非法容量:"+initialCapacity);}}//无参数构造,使用默认大小为10的空数组,构造方法中不设置数组长度,后续调用add方法时会扩容publicArrayList(){this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}//将一个参数为Collection的集合转换为ArrayList(其实就是将集合中的元素替换成数组的形式)。//如果传入的集合为null(调用c.toArray()方法时)会抛出空指针异常publicArrayList(Collectionc){elementData=c.toArray();if((size=elementData.length)!=0){//c.toArray()可能无法正确返回Object[]数组,然后使用Arrays.copyOf()方法if(elementData.getClass()!=Object[].class)elementData=Arrays.copyOf(elementData,size,Object[].class);}else{//如果集合转数组后数组长度为0,直接用自己的空成员变量初始化elementDatathis.elementData=EMPTY_ELEMENTDATA;}}图分析:比如Listlist2=newArrayList<>();结果list2为空,指向一个staticfinalObject[],添加元素时,elementData指向elementData[10](DEFAULT_CAPACITY=10),size为逻辑长度加一。添加、增长、底层分析工具publicbooleanadd(Ee){//因为需要添加元素,添加后容量可能不够,所以添加前需要判断(扩展)ensureCapacityInternal(size+1);//递增modCount!!后面会介绍到fast-fail!!//但是调用了这个扩展方法。不需要调用add()方法。其实已经调用过了,modCount加1了。//将值e放入对应的elementData[]下标数组elementData[size++]=e;返回真;}privatevoidensureCapacityInternal(intminCapacity){ensureExplicitCapacity(calculateCapacity(elementData,minCapacity));}//如果底层数组是默认缓存数组,取两个参数中较大的值继续调用是一个空数组//(在不带参数构造时使用,elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA)//如果是,则比较size+1(第一次调用add时size+1=1)和DEFAULT_CAPACITY,//那么显然容量为10if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){}返回最小容量;}privatevoidensureExplicitCapacity(intminCapacity){//记录修改次数modCount++;//溢出//如果传入的值大于底层数组的长度,则继续增长方法。//溢出意识代码if(minCapacity-elementData.length>0)grow(minCapacity);}privatestaticfinalintMAX_ARRAY_SIZE=Integer.MAX_VALUE-8;privatevoidgrow(intminCapacity){//oldCapacity是旧数组的容量intoldCapacity=elementData.length;//newCapacity为新数组的容量(oldCap+oldCap/2:旧容量的1.5倍)intnewCapacity=oldCapacity+(oldCapacity>>1);//检查新容量的大小是否小于所需的最小容量,如果小于,则最小容量为数组的新容量if(newCapacity-minCapacity<0)newCapacity=minCapacity;//如果新容量大于MAX_ARRAY_SIZE,则使用hugeCapacity比较两者if(newCapacity-MAX_ARRAY_SIZE>0)newCapacity=hugeCapacity(minCapacity);//minCapacity通常接近大小,所以这是一个胜利://复制原始数组中的元素elementData=Arrays.copyOf(elementData,newCapacity);}privatestaticfinalintMAX_ARRAY_SIZE=Integer.MAX_VALUE-8;@NativepublicstaticfinalintMAX_VALUE=0x7fffffff;privatestaticinthugeCapacity(intminCapacity){if(minCapacity<0)//溢出抛出newOutOfMemoryError();//比较minCapacity和MAX_ARRAY_SIZE//如果minCapacity很大,使用Integer.MAX_VALUE作为新数组的大小//如果MAX_ARRAY_SIZE很大,使用MAX_ARRAY_SIZE作为新数组的大小//MAX_ARRAY_SIZE=Integer.MAX_VALUE-8;返回(最小容量>MAX_ARRAY_SIZE)?Integer.MAX_VALUE:MAX_ARRAY_SIZE;}//工具类publicstaticT[]copyOf(U[]original,intnewLength,ClassnewType){@SuppressWarnings("unchecked")T[]copy=((Object)newType==(Object)Object[].class)?(T[])新对象[newLength]:(T[])Array.newInstance(newType.getComponentType(),newLength);System.arraycopy(original,0,copy,0,Math.min(original.length,newLength));返回副本;}//System.arraycopy()方法,native方法,so直接只用这个方法会获得高性能//这也是具体扩展的具体底层实现publicstaticnativevoidarraycopy(Objectsrc,intsrcPos,Objectdest,intdestPos,intlength);//src:源数组//srcPos:从源数组的srcPos位置开始移动//dest:目标数组//desPos:从源数组的srcPos位置开始移动的元素,这些元素从目标数组的desPos开始填充//length:移动源数组的长度扩展:newCapacity为新数组的容量(oldCap+oldCap/2:即更新为旧容量的1.5倍)remove方法分析1.remove(intindex)删除根据给下标publicEremove(intindex){rangeCheck(index);//检查下标是否合法(如果index>size,抛出IndexOutOfBoundsException)modCount++;//修改列表结构,需要更新这个值EoldValue=elementData(index);//直接在数组中找到这个值intnumMoved=size-index-1;//这里计算需要移动的次数//如果这个值大于0,说明还有后续元素需要移动到theleft(size=index+1)//如果为0,则表示被移动要移除的对象是最后一个元素(不需要移动其他元素)if(numMoved>0)//移动所有元素仅在左侧索引索引处覆盖索引位置处的元素System.arraycopy(elementData,index+1,elementData,index,numMoved);//移动后,原数组中size位置为nullelementData[--size]=空;//清除让GC做它的工作//返回旧值returnoldValue;}2.remove(Objecto)按元素删除,并删除第一个与参数匹配的元素publicbooleanremove(Objecto){//如果element为null,遍历数组去掉第一个nullif(o==null){for(intindex=0;index0)System.arraycopy(elementData,index+1,elementData,index,numMoved);元素数据[--大小]=空;//清除让GC做它的工作}fail-fast在系统设计中,fail-fastsystem立即报告任何可能指示故障的情况的系统。快速故障系统通常旨在停止正常操作,而不是尝试继续可能有缺陷的过程。这种设计通常会在运行的多个点检查系统状态,以便及早发现任何故障。fail-fast模块的职责是检测错误,然后让系统的下一个最高级别处理错误。Java集合类中很多地方都使用了这种机制进行设计。一旦使用不当,就会触发fail-fast机制设计的代码,出现意想不到的情况。我们通常所说的Java中的fail-fast机制,是指Java集合默认的一种错误检测机制。当多个线程对某些集合进行结构更改时,可能会触发该机制,然后抛出并发修改异常ConcurrentModificationException。但是,如果不是在多线程环境下,如果在foreach遍历过程中使用add/remove方法,也可能会抛出这个异常。publicbooleanadd(Ee){ensureCapacityInternal(size+1);//递增modCount!!后面会介绍到fast-fail!!//但是调用了这个扩展方法。不需要调用add()方法。其实已经调用过了,modCount加了1。elementData[size++]=e;返回真;Arraylist和Vector的区别用的比较少。publicclassVectorextendsAbstractList//实现List接口implementsList,RandomAccess,Cloneable,java.io.Serializable{//底层数组实现protectedObject[]elementData;受保护的int元素计数;protectedintcapacityIncrement;向量源码分析//synchronized关键字的声明publicsynchronizedbooleanadd(Ee){modCount++;//检查是否展开ensureCapacityHelper(elementCount+1);//赋值元素数据[elementCount++]=e;返回真;}None作为例外,只要是关键操作,都会在方法前加上synchronized关键字,保证线程安全。区别:扩容后是原来容量的两倍。参考链接https://juejin.cn/post/684490...https://zhuanlan.zhihu.com/p/...https://juejin.cn/post/698127...