Java實現(xiàn)ArrayList自動擴容
一.為什么要進行擴容
1.1ArrayLiat底層介紹
ArrayList`是 Java 中的一個常用集合類,其內(nèi)部實現(xiàn)是基于數(shù)組的,可以通過下標來訪問和修改其中的元素。在操作 `ArrayList` 時,如果我們向其中添加的元素個數(shù)超過了已分配的數(shù)組長度,則需要對數(shù)組進行擴容。這也是 `ArrayList` 能夠自動擴容的原因。
1.2擴容原因:
下面是對 ArrayList 擴容的必要性進行解釋:
1. 提高效率
數(shù)組在內(nèi)存中是一段連續(xù)的空間,在同一時間內(nèi),其所有元素的空間是連續(xù)的。在 `ArrayList` 中,當我們需要向其中添加元素時,如果發(fā)現(xiàn)當前數(shù)組的長度已經(jīng)達到了其最大值,我們就需要對其進行擴容。擴容的意思是在內(nèi)存中重新分配一個可以容納更多元素的連續(xù)空間,并將原有數(shù)組的元素復(fù)制到新的空間中。這樣,我們就可以向新的空間中添加元素了。通過擴容,我們避免了在數(shù)組中頻繁移動元素,提高了程序的效率。
2. 避免數(shù)組下標越界
當我們訪問數(shù)組時,如果使用的下標超出了數(shù)組的實際長度,則會發(fā)生數(shù)組下標越界異常。擴容可以避免這種情況發(fā)生,因為擴容會重新分配更大的內(nèi)存空間,并修改數(shù)組的長度,使得我們可以在新的空間中添加元素,避免了訪問數(shù)組時下標越界的問題。
3. 降低內(nèi)存碎片
擴容可以避免內(nèi)存碎片的產(chǎn)生。在執(zhí)行增刪操作時,如果數(shù)組中存在空洞,即有些位置的元素被刪除后,造成數(shù)組遠小于原來的大小,這時也需要重新分配內(nèi)存空間。如果這種情況發(fā)生頻繁,會導致內(nèi)存空間的碎片化,使得程序性能變差。而數(shù)組的擴容操作在內(nèi)存中分配連續(xù)空間,可以避免這種問題的出現(xiàn),從而降低內(nèi)存碎片的產(chǎn)生。
1.3什么是內(nèi)存碎片化?
1.3.1定義:
指在程序運行過程中,由于空間的分配和釋放不規(guī)則,形成了很多不連續(xù)、空閑的內(nèi)存片段,使得原本容易找到連續(xù)空間的程序運行變得困難。內(nèi)存中的空閑區(qū)域是不連續(xù)的,當需要分配一個大段的內(nèi)存時,就會因為找不到足夠的連續(xù)空間而產(chǎn)生問題。這種情況常常發(fā)生在反復(fù)分配和釋放內(nèi)存的場景中,例如大數(shù)據(jù)量的操作或多次執(zhí)行動態(tài)數(shù)組擴容等。
1.3.2解決方法
內(nèi)存空間的碎片化會對系統(tǒng)性能產(chǎn)生負面影響,因為程序在分配或釋放內(nèi)存時需要不停地將內(nèi)存碎片合并或分割,這樣會浪費更多的時間和系統(tǒng)資源。在程序的現(xiàn)代化中,應(yīng)該盡可能地避免或減少內(nèi)存碎片的出現(xiàn),從而優(yōu)化程序性能。
以下是幾種減少內(nèi)存碎片的方法:
- 使用內(nèi)存池技術(shù),固定分配一部分內(nèi)存塊供程序使用。
- 動態(tài)分配時,采用內(nèi)存對齊方式,盡量使得分配出來的內(nèi)存塊尺寸是確定的。
- 盡量減少對象的分配與回收,從而降低內(nèi)存碎片化的程度。
- 對于數(shù)據(jù)結(jié)構(gòu)動態(tài)增長的場景,采用增量式擴容的策略,避免一次性分配過大的內(nèi)存空間。
二.進行ArrayLiat擴容操作
1.擴容的底層原理:
ArrayList 自動擴容的實現(xiàn):依賴于 `ensureCapacityInternal()` 和 `grow()` 兩個方法。
當添加一個新元素到 ArrayList 時,ArrayList 會先判斷當前存儲元素的數(shù)組容量是否已經(jīng)達到了最大大?。?`Integer.MAX_VALUE`),如果已經(jīng)達到了則不再擴容。否則,如果當前存儲元素的數(shù)組容量已經(jīng)滿了,那么就需要擴容:
1. `ensureCapacityInternal()` 方法會先計算出新的容量大小:原來的容量大?。ㄓ洖?oldCapacity)加上原來的容量大小的一半(即 oldCapacity >> 1)。
2. 如果新的容量大小小于當前所需的容量(即當前 arrayList 的大小加 1),則新容量大小為當前所需的容量加 1。
3. `grow()` 方法會創(chuàng)建一個新的存儲元素的數(shù)組,其大小就是新的容量大小。然后它會調(diào)用 `Arrays.copyOf()` 方法來將舊數(shù)組中的元素復(fù)制到新數(shù)組中。
最后,ArrayList 會將新的數(shù)組作為內(nèi)部存儲數(shù)組,并更新相關(guān)信息。
這樣,每次擴容的大小為原數(shù)組大小的約1.5倍,這個值是可以設(shè)置的,通過 `ensureCapacity()` 方法來調(diào)整。如果需要添加很多元素,建議預(yù)估需要的大小,調(diào)用 `ensureCapacity()` 來避免頻繁的擴容操作,提高性能。
2.實現(xiàn)操作
2.1代碼截屏:

2.2效果圖:

2.3注意事項:
1.ArrayList 默認長度為10,當然我們也可以設(shè)置長度為其他值
例如: ArrayList list=new ArrayList<>(50); 當我們打印集合長度是就為:50
好處:可以減少擴容次數(shù),提高程序在處理,運行時的速度
2. ArrayList 的增長因子為0.5倍數(shù),擴容倍數(shù)為1.5倍數(shù)!在進行擴容是數(shù)組長度在有小數(shù)時會向下取整比如說:在效果圖數(shù)組長度15時:在添加第16個元素時擴容后的長度為:原來長度*0.5+原來長度(向下取整)=新長度;運用這個公式就可以得到新的擴容數(shù)組長度為22
2.4源碼:
package liuzhi_list;
import java.lang.reflect.Field;
import java.util.ArrayList;
public class demo1 {
public static void main(String[] args) throws Exception{
//首先創(chuàng)建一個arrayList 集合
ArrayList list=new ArrayList<>(50);
//通過for循環(huán)添加數(shù)據(jù) 添加100條
for (int i = 0; i<100; i++) {
list.add(i);
//打印輸出結(jié)果
System.out.print(i+"\r");
//發(fā)現(xiàn)集合通過for循環(huán)增加了100條數(shù)據(jù)
System.out.println("集合有多少數(shù)據(jù):"+list.size());
getLength(list);
}
}
/**
* 此方法通過調(diào)用arrayliat底層來操作
* @param list
* @throws Exception
* @throws Exception
*/
private static void getLength(ArrayList list) throws Exception, Exception {
//通過調(diào)用 獲取 ArrayList對象類部類獲取底層的elementData字段
Field f = list.getClass().getDeclaredField("elementData");
//因為arraylist底層是私有化 必須通過反射 并且打開私有化權(quán)限
f.setAccessible(true);
//作用是獲取 ArrayList 對象的底層數(shù)組
Object[] object = (Object[]) f.get(list);
//打印數(shù)組長度
System.out.println("當前數(shù)組長度: "+object.length);
}
}到此這篇關(guān)于Java實現(xiàn)ArrayList自動擴容的文章就介紹到這了,更多相關(guān)Java ArrayList自動擴容內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用JAXBContext輕松實現(xiàn)Java和xml的互相轉(zhuǎn)換方式
這篇文章主要介紹了依靠JAXBContext輕松實現(xiàn)Java和xml的互相轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
Java基礎(chǔ)知識之CharArrayWriter流的使用
這篇文章主要介紹了Java基礎(chǔ)知識之CharArrayWriter流的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
spring boot中使用@Async實現(xiàn)異步調(diào)用任務(wù)
本篇文章主要介紹了spring boot中使用@Async實現(xiàn)異步調(diào)用任務(wù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02
全網(wǎng)最全最細的jmeter接口測試教程以及接口測試流程(入門教程)
本文主要介紹了全網(wǎng)最全最細的jmeter接口測試教程以及接口測試流程,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11

