[JAVA] Java 陣列、多維陣列,動態、靜態初始化,陣列JVM記憶體模型分析

老夫不正經發表於2020-03-22

陣列、多維陣列,靜態、動態初始化,都說明白了
]

什麼是陣列

所謂陣列,是具有相同資料型別的若干變數或者資料按照一定排序規則組合起來的一種資料儲存格式。陣列中的資料稱為陣列元素,我們使用索引來標識陣列元素在陣列中的儲存位置,索引從0開始,步長是1,其後的索引依次遞增:

陣列

其中,資料型別包括以下兩種:

  • 基本資料類byte,short,int,long,float,double,char,boolean
  • 引用資料型別類,介面,陣列,基本資料型別的包裝類也資料引用資料型別

Java中陣列的定義

陣列的定義

  • 方式1:資料型別[] 陣列名; 如:int[] ages; 推薦使用此方式建立陣列。
  • 方式2:陣列元素的型別 陣列名[]; int ages[]; 此方法不推薦

陣列的初始化

陣列必須先初始化,才能使用,也就是要先為陣列和陣列元素在JVM記憶體模型中分配空間,給每個陣列元素賦初始值,初始值可以在建立陣列時指定,也可以只指定陣列長度,然後使用對應資料型別的預設值作為其初始值,下圖是各個資料型別的預設值:

各個資料型別的預設值

null 表示沒有指向任何儲存空間,是空值;如果將null賦予物件,則表示該物件引用為空,將會被GC回收,使用此物件呼叫方法,或者運算元據會觸發NullPointerException(空指標異常)。

初始化陣列有兩種方式:靜態初始化動態初始化;但是無論以哪種方式初始化陣列,一旦初始化完成,陣列的長度就固定了,陣列中的元素個數也就已經固定了,不能改變,所以說陣列是固定長度的。

**陣列的靜態初始化:**由我們(程式設計師們)來為每一個陣列元素設定初始化值,也就是說知道要在陣列中儲存哪些資料;此時陣列的長度JVM根據設定的初始值來分配,不需要再設定

語法如下:

陣列的靜態初始化

建立陣列時,JVM也會為其分配資料儲存區域;所以,在JVM中建立一個陣列時記憶體模型是這樣的:

靜態初始化陣列的JVM記憶體模型

陣列的動態初始化: 由我們(程式設計師們)來設定陣列長度),而陣列中元素的初始值由JVM賦予;語法:

陣列的動態初始化

但是, 不能同時使用靜態初始化和動態初始化,比如:

int\[\] nums = new int\[3\]{13, 14, 520};  // 這種寫法是錯誤的。
複製程式碼

那麼什麼時候使用靜態初始化,什麼時候使用動態初始化呢

  • 如果提前知道需要儲存的資料,優先選用靜態初始化,否則使用動態初始化來建立陣列;
  • 知道陣列長度時,優先使用動態初始化;
  • 陣列長度和需要儲存的資料都知道時,兩種方式都可以,任選其一即可;

動態初始化陣列的JVM記憶體模型

陣列的基本操作

1.陣列基本操作:

  • 獲取元素: 元素型別 變數 = 陣列名[index];
  • 設定元素: 陣列名[index] = 值;
  • 陣列長度: int len = 陣列名.length; 注意這裡的length是屬性,不是方法,從呼叫上方式上也能看出來;
  • 索引範圍: 從0開始,逐一遞增. 直至 length-1:[0,length-1]
  • 最大值:getMax()
  • 最小值:getMin()

2.運算元組常見異常:

  • NullPointerException:空指標異常,陣列或者變數未初始化就直接操作時會觸發;
  • ArrayIndexOutOfBoundsException:陣列的索引越界異常,獲取陣列元素時使用的索引超出了陣列的索引範圍時會觸發。

3.獲取元素在陣列中的位置索引:

  • 元素在陣列中第一次出現的位置的索引:indexOf()
  • 元素在陣列中最後一次出現的位置的索引:lastIndexOf()

陣列在main函式中的應用

main函式中的陣列

​ 可以接收傳入的引數,一般是提供給使用者傳入引數來完成一些特定的操作的。

多維陣列

多維陣列:以陣列為資料型別建立陣列,也就是陣列中的陣列,如:二維陣列可以這樣來初始化:

靜態初始化

多維陣列靜態初始化

動態初始化

多維陣列動態初始化

多維陣列的取值

int\[1\]\[1\] : 表示第2個一維陣列的第2個元素;
複製程式碼

建立多維陣列時,JVM為多維陣列分配記憶體;所以,多維陣列的記憶體模型在JVM 中是這樣的:

多維陣列的JVM記憶體模型

  • 一維陣列:陣列中的每一個元素都是一個值(基本型別或者引用型別)。
  • 二維陣列:陣列中的每一個元素是一個一維陣列。
  • 三維陣列:陣列中的每一個元素是一個二維陣列。

依次類推。

楊輝三角

楊輝三角就是一個典型的多維陣列例項:它的規律是每行起始和結束兩個數都是1,每個數都等於它的上方兩個數之和,詳情如下圖所示:

楊輝三角

楊輝三角是二項式係數在三角形中的一種幾何排列,最早出現於北宋賈憲的《黃帝九章算經細草》,後被南宋數學家楊輝抄錄於《詳解九章演算法》一書。在Java中可以使用多維陣列列印楊輝三角,程式碼如下:

楊輝三角的程式碼例項

foreach

我們在使用迴圈迭代陣列的時候,有時候並不關心迭代元素的索引,迭代陣列元素的時候,直接運算元組元素,不關心運算元組的索引。所以,從Java5開始(JDK1.5)開始,Java提供了一種新的語法,foreach(增強for迴圈)語法如下:

增強for迴圈語法

通過foreach,我們便可以快速迭代出陣列中的元素:

增強for迴圈例項

接下來,通過反編譯位元組碼檔案,看看JVM是如何實現foreach的:

JVM中的增強for迴圈

不難發現,foreach其實在底層依然是使用for迴圈+索引來運算元組的,雖然把foreach稱為增強for迴圈,但其底層依然是使用for迴圈實現的,我們將其稱之為語法糖,目的就是為了吸引開發者,讓開發者寫更少的程式碼,這恰恰也是開發者們樂意願意看到的。

foreach雖然會少些很多程式碼,但論效能,靈活性卻不如for迴圈,所以如果只關心元素而不關心索引,首選foreach,其他情況下還是應該for迴圈;在集合中也是這樣的道理。

方法的可變引數

Java5還有另一個新特性:方法的可變引數,這裡可變說的是引數的個數可變,並不是引數值可變,看如下的程式碼中,方法getArgsLength便使用了可變引數:

可變引數例項

還是將其反編譯,檢視JVM對可變引數的實現;不難發現,方法的可變引數其實也是一個語法糖,因為其底層還是一個陣列,因此,可以把可變引數型別當做一個陣列來處理,比如元素輸出:

可變引數的JVM實現

可變引數的使用注意

  1. 可變引數必須作為方法的最後一個引數,避免與其他引數產生歧義,引發異常;
  2. 方法最多隻能有一個可變引數。

完結。老夫雖不正經,但老夫一身的才華

相關文章