
1.说说ArrayList
1.基本原理
ArrayList,原理就是底层基于数组来实现。
01.基本原理:
数组的长度是固定的,java里面数组都是定长数组,比如数组大小设置为100,此时你不停的往ArrayList里面塞入这个数据,此时元素数量超过了100以后,此时就会发生一个数组的扩容,就会搞一个更大的数组,把以前的数组拷贝到新的数组里面去。
这个数组扩容+元素拷贝的过程,相对来说会慢一些
02.缺点:
01:不要频繁的往arralist里面去塞数据,导致他频繁的数组扩容,避免扩容的时候较差的性能影响了系统的运行。
02: 数组来实现,数组你要是往数组的中间加一个元素,是不是要把数组中那个新增元素后面的元素全部往后面挪动一位,所以说,如果你是往ArrayList中间插入一个元素,或者随机删除某个元素,性能比较差,会导致他后面的大量的元素挪动一个位置。
03.优点:
基于数组来实现,非常适合随机读,你可以随机的去读数组中的某个元素。
例如:list.get(10),相当于是在获取第11个元素,这个随机读的性能是比较高的,随机读,list.get(2),list.get(20),随机读list里任何一个元素。
因为基于数组来实现,他在随机获取数组里的某个元素的时候,性能很高,他可以基于他底层对数组的实现来快速的随机读取到某个元素,直接可以通过内存地址来定位某个元素。
04.常用场景:
ArrayList,常用,如果你不会频繁的在里面插入一些元素,不会导致频繁的元素的位置移动、数组扩容,就是有一批数据,查询出来,灌入ArrayList中,后面不会频繁插入元素了,主要就是遍历这个集合,或者是通过索引随机读取某个元素。
如果果你涉及到了频繁的插入元素到list中的话,尽量还是不要用ArrayList,数组,定长数组,长度是固定的,元素大量的移动,数组的扩容+元素的拷贝。
05.场景示例:
开发系统的时候,大量的场景,需要一个集合,里面可以按照顺序灌入一些数据,ArrayList的话呢,他的最最主要的功能作用,就是说他里面的元素是有顺序的,我们在系统里的一些数据,都是需要按照我插入的顺序来排列的。
2.源码剖析
01.核心方法的剖析
咱们来启动一个demo工程,在里面写写集合的代码,跟进去看看各种集合的实现原理,直接可以看JDK底层的源码。
(1).示例代码:
publicclassArrayListDemo {publicstaticvoidmain(String[] args){
ArrayList<String> sayLove =new ArrayList<String>();
sayLove.add("老婆,早上好");
sayLove.add("老婆,下午好");
sayLove.add("老婆,下班啦,我去找你");
sayLove.set(0,"老婆,早上好,我们一起吃早饭吧");
sayLove.add(2,"老婆,注意坐姿,不要久坐哦");
}
}
(2).构造函数分析:
默认的构造函数,直接初始化一个ArrayList实例的话,会将内部的数组做成一个默认的空数组,{},Object[],他有一个默认的初始化的数组的大小的数值,是10,也就是我们可以认为他默认的数组初始化的大小就是只有10个元素。
privatestaticfinal Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//空数组this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
privatestaticfinalint DEFAULT_CAPACITY = 10;//初始容量 10注意点:
ArrayList的话,玩儿好的话,一般来说,你应该都不是使用这个默认的构造函数,你构造一个ArrayList的话,基本上来说就是默认他里面不会有太频繁的插入、移除元素的操作,大体上他里面有多少元素,你应该可以推测一下的。
基本上最好是给ArrayList构造的时候,给一个比较靠谱的初始化的数组的大小,比如说,100个数据,1000,10000,避免数组太小,往里面塞入数据的时候,导致数据不断的扩容,不断的搞新的数组。
ensureCapacityInternal(size + 1); // Increments modCount!!
你每次往ArrayList中塞入数据的时候,人家都会判断一下,当前数组的元素是否塞满了,如果塞满的话,此时就会扩容这个数组,然后将老数组中的元素拷贝到新数组中去,确保说数组一定是可以承受足够多的元素的。
(3).add(E)方法
日常多表白,恩爱不懈怠。
分析如下:
publicbooleanadd(E e){
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
returntrue;
}
#2 ensureCapacityInternal(size + 1);:判断一下当前的数组容量是不是满了,如果满了会进行扩容;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
1).第一次进入这个方法时,minCapacity=10,默认值,而此时底层还是个空数组,自然会进行数组的扩容。扩容代码如下:
privatevoidgrow(int minCapacity){
// overflow-conscious codeint oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
ArrayList基于数组实现,适合随机读取但不适用于频繁插入。数组扩容会导致性能下降,尤其是中间插入和删除元素。建议预估初始容量以减少扩容操作。在Java中,ArrayList添加元素时会检查容量,必要时进行扩容,扩容过程包括创建新数组和拷贝旧元素。
297

被折叠的 条评论
为什么被折叠?



