天天看點

《java練級之路》之數組為什麼成為引用類型

🌀🌀🌀作者:@小魚不會騎車

🍁🍁🍁專欄:《java練級之旅》

🎀🎀🎀個人簡介:一名專科大一在讀的小比特,努力學習程式設計是我唯一的出路😎😎😎

《java練級之路》之數組為什麼成為引用類型
🙈🙈🙈作者心裡話
小魚一直都是秉承着“開開心心看部落格,快快樂樂學知識”這個觀點來給大家用一些接地氣的話進行講解,可能會有人覺得小魚太墨迹了,小魚這裡也很樂意接受大家的意見,會進行采納,大家也可以指出小魚的不足,小魚也會積極的進行改變,總之,願我們越來越優秀

前言

在這篇文章中,小魚會細緻的講解大家在初識java時對于java中數組的認知,前面一篇文章講解了數組的建立及初始化,那麼這片文章呢,就會講到關于數組在記憶體中是如何存儲的,準備好了嗎各位開始發車了😜

《java練級之路》之數組為什麼成為引用類型

(數組是引用類型)

🍎 初識JVM的記憶體分布

💡在我們的java中,記憶體是一段連續的存儲空間,主要用來存儲程式運作時資料的。比如:

  1. 程式運作時代碼需要加載到記憶體
  2. 程式運作産生的中間資料要存放在記憶體
  3. 程式中的常量也要儲存
  4. 有些資料可能需要長時間存儲,而有些資料當方法運作結束後就要被銷毀
如果對記憶體中存儲的資料不加區分的随意存儲,那對記憶體管理起來将會非常麻煩。

是以JVM也對所使用的記憶體按照功能的不同進行了劃分:

《java練級之路》之數組為什麼成為引用類型

總共有五部分,

  • 程式計數器 (PC Register): 隻是一個很小的空間, 儲存下一條執行的指令的位址
  • 虛拟機棧(JVM Stack): 與方法調用相關的一些資訊,每個方法在執行時,都會先建立一個棧幀,棧幀中包含有:局部變量表、操作數棧、動态連結、傳回位址以及其他的一些資訊,儲存的都是與方法執行時相關的一些資訊。比如:局部變量。當方法運作結束後,棧幀就被銷毀了,即棧幀中儲存的資料也被銷毀了。
  • 本地方法棧(Native Method Stack): 本地方法棧與虛拟機棧的作用類似. 隻不過儲存的内容是Native方法的局部變量.在有些版本的 JVM 實作中(例如HotSpot), 本地方法棧和虛拟機棧是一起的。
  • 堆(Heap): JVM所管理的最大記憶體區域. 使用 new 建立的對象都是在堆上儲存 (例如前面的 new int[]{1, 2,3} ),堆是随着程式開始運作時而建立,随着程式的退出而銷毀,堆中的資料隻要還有在使用,就不會被銷毀。
  • 方法區(Method Area): 用于存儲已被虛拟機加載的類資訊、常量、靜态變量、即時編譯器編譯後的代碼等資料. 方法編譯出的的位元組碼就是儲存在這個區域

但是我們在學習這一篇的内容時隻會涉及到棧區和堆區,稍後會進行詳細講解。

🍎 基本類型變量與引用類型變量

🍓1. 基本資料類型和引用類型變量

🐵我們接下來用三種方式開辟數組

int[]array1={1,2,3,4};//開辟一個靜态數組
int[]array2=new int[]{1,2,3,4};//同上(new int []可以舍去)
int[]array3=new int[4];//開辟一個動态數組
           

這是一個int類型,在記憶體中的存放方式如圖

int a=10;
           
《java練級之路》之數組為什麼成為引用類型

a在main函數裡是局部變量,是以在棧上配置設定記憶體。

那麼我們的數組呢?在記憶體中是如何存儲的?🧐

《java練級之路》之數組為什麼成為引用類型

在記憶體中,堆區比棧區大一些❗️❗️❗️

👉大家看,我們的第一個和第二個開辟數組的方式其實是一樣的,都是new一個空間出來,那麼new出來的空間是哪裡的呢?其實就是堆上的,我們從堆上開辟了一塊記憶體,用來存放這個而數組的值,

我們假設array1在堆中開辟記憶體的位址是0x123,那麼我們變量array1存放的就是0x123,也就是存放堆上開辟空間的位址。

《java練級之路》之數組為什麼成為引用類型

🌈大家剛才看到了

int a=10

,在棧上存放的是int類型的資料,但是

int[]arry1

是一個引用類型,存放的是堆上開辟的記憶體的位址,那我們就可以稱array1這種變量為引用變量(引用),這時候我們就可以通過array1引用變量中存放的位址,找到這塊開辟的記憶體空間,

✅專業術語:array1指向了一個對象,這個對象就是在堆上開辟的記憶體

《java練級之路》之數組為什麼成為引用類型

就這樣,我們就可以通過這個位址找到這塊空間。

int a=10;
int []array={1,2,3,4};
           

✅總結上述代碼

  • a,array都是函數内部建立的變量,是以,其空間都在main方法對應的棧幀中配置設定。
  • a是内置類型的變量,是以其空間儲存的就是給該變量初始化的值。
  • array是數組類型的引用變量,其内部儲存的内容可以簡單了解成,是數組在堆空間中的首位址。
《java練級之路》之數組為什麼成為引用類型

🍎 再談引用變量

🍓 1. 第一道基礎題

接下來給大家看一串代碼

int[]array1={1,2,3,4};
        array1[0]=99;
        int[]array2=array1;
        array2[0]=100;
        System.out.println(Arrays.toString(array1));
        System.out.println(Arrays.toString(array2));
           

🐻大家猜第一個列印什麼第二個列印什麼?

大家現在可以暫時思考一下,心中有答案之後再往下劃,看看答案是不是跟自己想的一樣。

《java練級之路》之數組為什麼成為引用類型
《java練級之路》之數組為什麼成為引用類型

🐧好的,接下來就會給大家進行解析,我們先把代碼拷貝到畫圖闆

1️⃣我們現在進行了第一步,開辟空間,

《java練級之路》之數組為什麼成為引用類型

2️⃣将首元素改為99

《java練級之路》之數組為什麼成為引用類型

3️⃣将array1的值給array2

《java練級之路》之數組為什麼成為引用類型

我們将a指派給b我們的b就是10,那我們把array1給array2呢?因為我們的array1中存放的是位址,是以我們把array1的值指派給array2就是把位址指派給array2,如圖

《java練級之路》之數組為什麼成為引用類型

是以我們的array2指向的空間也是位址為0x123的空間,

4️⃣将array2[0]的值改為100

《java練級之路》之數組為什麼成為引用類型

因為我們array1和array2指向的同一塊空間,是以修改array2就就是修改array1,是以我們最後的輸出就是{100, 2, 3, 4}

綜合上述

《java練級之路》之數組為什麼成為引用類型

🍓 2. 第二道基礎題

🙈好的,大家再來看這串代碼(小魚又要挖坑了呦)

int[]array1={1,2,3,4};
        int[]array2={11,22,33,44};
        array1=array2;
        array1[0]=1234;
        System.out.println(Arrays.toString(array1));
        System.out.println(Arrays.toString(array2));
           

讓我們來思考思考,這個會輸出什麼呢?

答案就在下面

《java練級之路》之數組為什麼成為引用類型

輸出

《java練級之路》之數組為什麼成為引用類型

大家想到的答案和這個一樣嘛?

接下來小魚給大家講解

1️⃣第一步依舊是開辟一塊空間

《java練級之路》之數組為什麼成為引用類型

2️⃣就是把array2指派給array1

《java練級之路》之數組為什麼成為引用類型

這樣我們array1的存放的位址和array2存放的位址就一樣,我們就可以通過array1找到array2位址指向的空間,

3️⃣ 我們将array[0]的值改為1234,

《java練級之路》之數組為什麼成為引用類型

🐧好的,現在我們現在就可以發現,我們的array1和array2指向的是同一塊空間,并且我們的array1将下标為0的元素改為了1234,于是最後輸出就得到了我們上面的答案,當然,此時由于我們的array1找不到之前的空間了,是以之前開辟的空間就會被系統自動回收,不用擔心記憶體洩漏

✅結論

當兩個引用同時指向一塊對象時,通過其中任意一個引用去通路該對象并修改該對象的值,另一個引用去通路的時候,值也是被改變的

💡可以了解為對象時一個“空調”,我用這個“遙控器1”(array1)去修改它的溫度之後,我的“遙控器2”(array2)再去通路這個空調,就是已經被修改的溫度,當我的“遙控器2”去修改也是同理

🍎 認識null

🍓1. java中null注意事項

🌈在java當中局部變量一定要初始化不然會報錯❗️❗️❗️

《java練級之路》之數組為什麼成為引用類型

🍰我們的b是int類型可以指派個0初始化,但是我們的array4呢?他是個引用,他存的是位址,該怎麼做才能讓他不去指向别的變量呢。我們可以用null(小寫)這個就是空指針,當我們置成空指針時,array4就不指向任何對象了

int b=0;
        int[]array4=null;
        System.out.println(b);
        System.out.println(array4);
           
《java練級之路》之數組為什麼成為引用類型

☀️但是呢,在我們初始化為空指針後,如果我想要通路它的第0個元素,就會報錯。

int[]array4=null;
        System.out.println(array4[0]);
           
《java練級之路》之數組為什麼成為引用類型

🍒這個就是咱們以後會經常涉及到的問題,也可以成為NPE,意思是空指針異常,當出現這個問題的時候,就需要去檢查了,這裡是8

《java練級之路》之數組為什麼成為引用類型

😾這時候我們就需要根據提示

《java練級之路》之數組為什麼成為引用類型

🍀我們的發現array4是null,如果我們的引用是null我們通過這個引用不管去做任何事他都會報錯,

int[]array4=null;
        System.out.println(array4.length);
           

🍎 總結

  • 我們的數組是存放在哪裡
  • 如何通路到這個數組
  • 數組的值是如何被修改的
  • 在通路數組時需要注意的事項
  • 如何避免空指針異常