1.定義:同一類型數據的集合。數組 [ ] 是一個容器實體,實體在內存中需要關鍵字new新建。當沒有給實體賦值時,Java會給實體自動初始化。
好處:自動給數組中的元素從0開始編號,方便操作。
格式:
元素類型 [ ] 數組名 = new 元素類型 [ 元素個數或數組長度 ]
int [ ] arr = new int [ 5 ];
分析: 等號左面定義 數組名,存放在堆中新建的數組的首地址。右邊在堆中新建 數組。
操作數組元素:arr[ 0 ] ,通過數組名裏的首地址,訪問數組中對應角標的元素。
2.內存空間的劃分:
1.寄存器 : CPU處理的
2.本地方法區:和本地系統版本相關
3.方法區:類加載技術相關
4.棧內存
5.堆內存
棧:存儲的都是局部變量。凡是定義在方法中的變量都是局部變量。生命週期短,更新速度快。
局部變量所屬的作用域一旦結束,該變量就會自動釋放。(如for循環中定義的循環變量)
局部代碼塊:{ },定義一個區間,限定局部變量的生命週期,釋放內存。(大程序用,加載的變量多佔內存,考慮局部變量的釋放情況,不多見)
堆:存儲的是對象(數組也是對象),凡是new建立都在堆中。
堆裏面存的都是實體,數組和對象都是實體。實體的作用是封裝多個數據。
int [ ] arr = new int [ 5 ];
內存分析:
①主函數或其他函數先加載進 棧內存,在棧中給數組名arr開闢空間。
②然後通過new在堆內存中開闢一個數組實體空間,並分配一個內存地址(數組的首元素地址),簡潔用十六進制表示。數組中用角標表示每個元素位置。
③最後把實體的內存地址賦值給 arr。
數組名arr稱爲引用數據類型。C++叫指針,Java叫引用。
當沒有給實體賦值時,Java會給實體默認自動初始化:
byte short int long 默認0
double float 默認0.0或0.0f
boolean 默認false
char 默認 ' \u0000 '
引用型 默認NULL(比如定義未初始化二維數組時,內存分析第一維時存放的是NULL,分析到第二維的時候再把第二維的數組地址放到第一維內存替換NULL)
arr = null ;
取消引用類型的指向,arr是數組類型,引用數據類型是一種,只能指向實體。此時如果繼續操作數組,會報空指針異常java.lang.NullPointerException。
這時堆中的數組會被視爲垃圾,在不定時的時間內自動回收,Jvm中有垃圾回收機制,用於監測堆中的垃圾,不定時做回收動作(垃圾量多時回收)。(C++堆內存垃圾由程序員通過析構函數手動回收)
null不會用於基本數據類型
多個引用變量可以同時指向一個實體。
特點小結:
1.每一個實體都有首地址值。
2.堆內存中的每一個變量都有默認初始化值,根據類型不同而不同。
3.常見問題:
1.內存的劃分是在運行的時候進行的,編譯的時候不會檢查數組角標是否越界或數組空指針異常。
當訪問到數組中不存在的角標時,運行時會報數組角標越界異常java.lang.ArrayIndexOutOfBoundsException。
當引用型變量沒有任何實體指向時,還在用其操作實體,運行時就報空指針異常
java.lang.NullPointerException。
2.
System.out.print(arr); // 打印出 [I@5c3a5635
做測試的時候偶爾用一下,當你不知道這個變量接收的是什麼類型的實體時。看@左邊的即可。
[I@5c3a5635: 左邊表示實體類型,右邊表示實體的哈希值
5c3a5635: 數組實體的哈希值,哈希是一種算法,用來定義數組實體在內存當中存儲的位置(地址值)。Java是調用windows的哈希算法來算實體在內存中的存儲位置,開闢內存空間由windows說了算。
[ I : 表示實體類型 和 實體數據類型 ,這裏表示整型數組。
4.第二種定義格式:賦初始值
①常規new方式:元素類型 [ ] 數組名 = new 元素類型 [ ] { 元素1,… }
int [ ] arr = new int[ ] { 1,2,3 };
②靜態初始化方式:元素類型 [ ] 數組名 = { 元素1,... }
int [ ] arr = { 1,2,3 };
一點小差別:在重新賦值或傳參的時候。
定義選擇:
int [ ] arr = new int [ 5 ]; //需要一個容器,確定數組的長度,但是不明確容器的具體數據時。
int [ ] arr = { 1,2,3 }; //需要一個容器,存儲已知的具體數據。
習慣養成:數據只要一多,就用數組存起來。