1. 前言
數(shù)組是一種重要的數(shù)據(jù)結(jié)構(gòu),可以利用它作為基礎(chǔ)來(lái)實(shí)現(xiàn)很多復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。因此我們要深入理解數(shù)組的存儲(chǔ)原理和特點(diǎn),熟悉它的常用操作,重點(diǎn)掌握它在聲明、查詢、存儲(chǔ)、復(fù)制等操作時(shí)的效率,便于我們?cè)诮窈蟮膶W(xué)習(xí)和使用中能夠充分利用數(shù)組的優(yōu)勢(shì)。
2. 什么是數(shù)組?
數(shù)組(Array)是一種簡(jiǎn)單的復(fù)合數(shù)據(jù)類型,它是一組有序數(shù)據(jù)的集合。數(shù)組根據(jù)維度可以分為一維數(shù)組、二維數(shù)組和多維數(shù)組。
因?yàn)?strong>數(shù)據(jù)結(jié)構(gòu)的本質(zhì)就是存放數(shù)據(jù)的容器,所以我們可以找到它們?cè)谏钪械暮芏嘣?。如果把冰箱比作?jì)算機(jī)存儲(chǔ)的話,我們最常見(jiàn)到的雞蛋盒就是數(shù)組的最佳模型了,他們的很多特點(diǎn)甚至都非常相似。
3. 數(shù)組的特點(diǎn)
數(shù)組在內(nèi)存中是存儲(chǔ)在一段連續(xù)的空間中,這使得數(shù)組在讀取的時(shí)候非常高效。我們?cè)诒渲杏秒u蛋盒存放雞蛋也是利用了冰箱里一塊完整連續(xù)的空間,便于我們存取雞蛋的時(shí)候快速準(zhǔn)確而不是把雞蛋散落在各個(gè)角落里。但是雞蛋盒有一個(gè)缺點(diǎn)就是我們買(mǎi)來(lái)的時(shí)候它的容量是固定的,如果裝滿了就不能再擴(kuò)容了,數(shù)組也是一樣,在創(chuàng)建的時(shí)候必須確定長(zhǎng)度并且不能變更,使得數(shù)組不適用于元素需要頻繁增加和刪除的場(chǎng)景??偨Y(jié)起來(lái)數(shù)組和雞蛋盒同時(shí)具有以下三大特點(diǎn):
- 一致性:數(shù)組中的每個(gè)元素都具有相同的數(shù)據(jù)類型,我們生活中一般也只會(huì)在雞蛋盒中放置雞蛋而不會(huì)摻雜草莓;
- 有序性:數(shù)組中的元素是有序的,并且可以用唯一下標(biāo)來(lái)訪問(wèn);雞蛋盒也是有序的,甚至我們也可以對(duì)雞蛋盒中的格子編號(hào)來(lái)明確快速地指出是哪一個(gè)格子的雞蛋有裂紋;
- 不可變性:數(shù)組在初始化的時(shí)候長(zhǎng)度一旦確定,就不可以再變更;而雞蛋盒子一旦需要變更容量,我們就只能買(mǎi)一個(gè)新的盒子了。
4. 數(shù)組的幾個(gè)常用操作
了解了數(shù)組的特點(diǎn),我們來(lái)看下怎么使用他們。
4.1 聲明和賦值
- 只聲明數(shù)組,并未在堆內(nèi)存中開(kāi)辟空間
// 數(shù)據(jù)類型 [] 數(shù)組名稱 = null;
int [] array = null;
- 聲明數(shù)組的同時(shí)開(kāi)辟空間
// 數(shù)據(jù)類型 [] 數(shù)組名稱 = new 數(shù)據(jù)類型[長(zhǎng)度];
int [] array = new int[3];
- 聲明數(shù)組的同時(shí)開(kāi)辟空間、同時(shí)給數(shù)組插入元素
//數(shù)據(jù)類型 [] 數(shù)組名稱 = new 數(shù)據(jù)類型[]{元素1,元素2...};
int [] array = new int[]{1,2,3};
//數(shù)據(jù)類型 [] 數(shù)組名稱 = {元素1,元素2...}(上一種方法的縮寫(xiě),不建議);
int [] array = {1,2,3};
- 多維數(shù)組的聲明方式
//數(shù)據(jù)類型 對(duì)象數(shù)組[][] = new 數(shù)據(jù)類型[一維長(zhǎng)度][二維長(zhǎng)度];
int array[][] = new int[3][5];
聲明數(shù)組有以上幾種方式,因?yàn)閿?shù)組是引用數(shù)據(jù)類型,在棧內(nèi)存聲明、在堆內(nèi)存中開(kāi)辟連續(xù)的定長(zhǎng)空間,所以我們可以在下圖中看到第二種方式聲明數(shù)組的時(shí)候,其實(shí)是分步完成的,第一步開(kāi)辟了一個(gè)長(zhǎng)度為3的數(shù)組空間,第二步分別為數(shù)組的三個(gè)元素賦值。
4.2 遍歷和讀取
數(shù)組有一個(gè)屬性 length 表示數(shù)組的長(zhǎng)度,使得我們可以很方便的遍歷數(shù)組。這個(gè)長(zhǎng)度在開(kāi)辟空間的時(shí)候就已經(jīng)固定了,就像雞蛋盒子的容量一樣,而且不論格子里存放元素的數(shù)量是多少,它的容量都是恒定不變的。
// 聲明一個(gè)數(shù)組并賦值
int [] array = new int[5];
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;
//遍歷方式1:
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
//遍歷方式2:
for(int a:array){
System.out.println(a);
}
4.3 復(fù)制擴(kuò)容
前面我們提到,盒子里的雞蛋放不下只能去購(gòu)買(mǎi)新的盒子,數(shù)組也是一樣,容量不夠的時(shí)候只能去創(chuàng)建新的數(shù)組,并且將原有數(shù)組中的元素按照原來(lái)的序號(hào)復(fù)制到新的數(shù)組中去。
//為長(zhǎng)度為5的原數(shù)組擴(kuò)容一倍
//第一步:聲明初始數(shù)組
int [] array = new int[]{1,2,3,4,5};
//第二步:聲明一個(gè)容量為原始數(shù)組2倍的新數(shù)組
int [] newArray = new int[array.length*2];
//第三步:將元素復(fù)制到新數(shù)組中
for ( int i = 0; i < array.length; i++) {
newArray[i] = array[i]; `
}
說(shuō)到這里我們還要提一個(gè)細(xì)節(jié),就是數(shù)組的空間是連續(xù)的,不等同于數(shù)組的元素是連續(xù)的,我們可以在數(shù)組中的任意位置存放或不存放元素,就像我們可以在雞蛋盒子的任何一個(gè)格子里放或不放雞蛋,都不影響數(shù)組本身的特性。
4. java.util.Arrays
我們對(duì)數(shù)組進(jìn)行的操作其實(shí)很多都被封裝在一個(gè)叫做 Arrays 的工具類中了,它為數(shù)組封裝了一些常用的靜態(tài)方法,使得我們可以輕松的對(duì)數(shù)組實(shí)現(xiàn)查詢、排序、填充等操作,大家可以通過(guò)查看源代碼或 API 來(lái)了解他們的使用方法。前面我們講到的復(fù)制擴(kuò)容數(shù)組就可以用 Arrays.copyOf (原數(shù)組名,新數(shù)組長(zhǎng)度) 方法來(lái)輕松實(shí)現(xiàn)。
這里我們還要單獨(dú)提一下 asList () 方法,這個(gè)方法可以將數(shù)組轉(zhuǎn)換成 ArrayList,使我們有更多的手段來(lái)處理數(shù)組,比如追加元素、刪除元素、判斷某個(gè)元素是否在數(shù)組中等等,解決了數(shù)組長(zhǎng)度不能改變等特性給我們帶來(lái)的不便。
//聲明一個(gè)數(shù)組并賦值
Integer[] array = new Integer[5];
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;
ArrayList<Integer> arrayList = new ArrayList<Integer>(Arrays.asList(array));
System.out.println(arrayList);
輸出:[1,2,3,4,5]
boolean isExist = Arrays.asList(array).contains(1);
System.out.println(isExist);
輸出:true
5. 數(shù)組的應(yīng)用與思考
根據(jù)數(shù)組的特點(diǎn)我們可以發(fā)現(xiàn),數(shù)組的使用場(chǎng)景多是在讀取頻繁,增減較少最好是不需要增減的場(chǎng)合,在初始化數(shù)組的時(shí)候能夠確定元素的最大個(gè)數(shù),比如以下場(chǎng)景:
- 存儲(chǔ)某班級(jí)學(xué)生的語(yǔ)文成績(jī)時(shí)可以使用數(shù)組,元素長(zhǎng)度固定幾乎不需要增減,讀取高效
- 導(dǎo)入EXCEL模板數(shù)據(jù)的時(shí)候可以使用二維數(shù)組來(lái)儲(chǔ)存臨時(shí)數(shù)據(jù),充分利用了數(shù)組讀取效率高的特性
對(duì)于動(dòng)態(tài)增加和減少元素的場(chǎng)景,我們可以使用剛剛提到的 ArrayList,后面的章節(jié)我們會(huì)對(duì)這部分內(nèi)容做詳細(xì)介紹。
這里分享一個(gè)有意思的小插曲,我在制做上面圖片敲代碼的時(shí)候手誤寫(xiě)了這樣一行代碼,小伙伴們可以結(jié)合第二行和第三行的執(zhí)行結(jié)果來(lái)解釋一下第一行代碼的實(shí)現(xiàn)結(jié)果。
int [] array = new int[]{};
System.out.println(array.length);
array[0] = 1;
6. 小結(jié)
本節(jié)我們知道了數(shù)組是一組有序數(shù)據(jù)的集合,它的特點(diǎn)一致性、有序性和不可變性,因此它的讀取效率高,增加或刪除元素的效率低。此外我們要熟練掌握數(shù)組的聲明方法和基本操作,作為一個(gè)基本數(shù)據(jù)結(jié)構(gòu),了解它的原理和擴(kuò)容方式還將有助于我們后面鏈表等知識(shí)的學(xué)習(xí)。