IT兄弟連 Java語法教程 數組 深入數組 記憶體中的數組

  • 2019 年 10 月 5 日
  • 筆記

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://blog.csdn.net/ITXDL123/article/details/97704576

數組是一種引用數據類型,數組引用變數只是一個引用,數組元素和數組變數在記憶體里是分開存放的。下面將深入介紹數組在記憶體中的運行機制。

記憶體中的數組

數組引用變數只是一個引用,這個引用變數可以指向任何有效的記憶體,只有當該引用指向有效記憶體後,才可以通過該數組變數來訪問數組元素。

與所有引用變數相同的是,引用變數是訪問真是對象的根本方式。也就是說,如果希望在程式中訪問數組對象本身,則只能通過這個數組的引用變數來訪問它。

實際的數組對象被存儲在堆記憶體中;如果引用該數組對象的數組引用變數是一個局部變數,那麼它被存儲在棧記憶體中。數組在記憶體中的存儲示意圖如圖3所示。

圖3 數組在記憶體中的存儲示意圖

如果需要訪問如圖3所示堆記憶體中的數組元素,則程式只能通過p[index]的形式實現。也就是說,數組引用變數是訪問堆記憶體中數組元素的根本方式。

如果堆記憶體數組不再有任何引用變數指向自己,則這個數組將成為垃圾,該數組所佔的記憶體將會被系統的垃圾回收機制回收。因此,為了讓垃圾回收機制回收一個數組所佔的記憶體空間,可以將該數組變數賦值為null,也就切斷了數組引用變數和實際數組之間的引用關係,實際的數組也就成了垃圾。

只要類型相互兼容,就可以讓一個數組變數指向另一個實際數組,這種操作會讓人產生數組的長度可變的錯覺。如下程式碼所示。

public class ArrayInRam{

public static void main(String[] args){

int[] a = {5,6,1};

int[] b = new int[4];

System.out.println("b數組的長度為:" + b.length);

for(int i = 0,len = a.length; i<len; i++){

System.out.println(a[i]);

}

for(int i = 0,len = b.length; i<len; i++){

System.out.println(b[i]);

}

b = a;

System.out.println("b數組的長度為:" + b.length);

}

}

運行上面程式碼後,將可以看到先輸出b數組的長度為4,然後依次輸出a數組和b數組的每個元素,接著會輸出b數組的長度為3.看起來視乎數組的長度是可變的,但這只是一個假象。必須牢記:定義並初始化一個數組後,在記憶體中分配了兩個空間,一個用於存放數組的引用變數,另一個用於存放數組本身。下面將結合示意圖來說明上面程式的運行過程。

圖4 定義並初始化a、b兩個數組後記憶體示意圖

當程式定義並初始化了a、b兩個數組後,系統記憶體中實際上產生了4塊記憶體區域,其中棧記憶體中有兩個引用變數:a和b;堆記憶體中也有兩塊記憶體區域,分別用於存儲a和b引用所指向的數組本身。此時電腦記憶體的儲存示意圖如圖5.4所示。

從圖4中可以非常清楚地看出a引用和b引用各自所引用的數組對象,並可以很清楚地看出a變數所引用的數組長度是3,b變數所引用的數組長度是4。

當執行上面程式中的程式碼b = a時,系統將會把a的值賦給b,a和b都是引用類型變數,存儲的是地址。因此把a的值賦給b後,就是讓b指向a所指向的地址。此時電腦記憶體的存儲示意圖如圖5所示。

圖5 讓b引用指向a引用所指向的數組後的存儲示意圖

從圖5中可以看出,當執行了b = a之後,堆記憶體中的第一個數組具有了兩個引用;a變數和b變數都引用了第一個數組。此時第二個數組失去了引用,變成垃圾,只有等待垃圾回收機制來回收它,但是它的長度依然不會改變,直到它徹底消失。