深入淺出Java數組及其內存機制

Java數組概述

數組(Array), 是多個相同類型數據按一定順序排列的集合, 並使用一個名字命名, 並通過編號的方式對這些數據進行統一管理。

相關概念

  • 數組名
  • 元素
  • 下標(或索引)
  • 數組的長度;元素的個數

數組的特點

  1. 數組本身是引用數據類型, 而數組中的元素可以是任何數據類型, 包括
    基本數據類型和引用數據類型。
  2. 創建數組對象會在內存中開闢一整塊連續的空間, 而數組名中引用的是
    這塊連續空間的首地址。
  3. 數組的長度一旦確定, 就不能修改。
  4. 我們可以直接通過下標(或索引)的方式調用指定位置的元素, 速度很快。
  5. 數組是有序排列的

數組的分類

按照維度進行分類

一維數組、 二維數組、 三維數組、 …

按照元素的數據類型分

基本數據類型元素的數組、 引用數據類型元素的數組(即對象數組)

數組使用

一維數組

聲明方式

type var[] 或 type[] var

Java語言中聲明數組時不能指定其長度(數組中元素的數)

初始化

動態初始化

數組聲明且爲數組元素分配空間與賦值的操作分開進行

int[] arr = new int[3 ];
arr[0] = 3;
arr[1] = 9;
arr[2] = 8;
靜態初始化

在定義數組的同時就爲數組元素分配空間並賦值。

int arr[] = new int[]{3, 9, 8};
int[] arr1 = {3,9,8};

數組元素的引用

定義並用運算符new爲之分配空間後,纔可以引用數組中的每個元素。

數組元素的引用方式
數組名[數組元素下標]
  • 數組元素下標可以是整型常量或整型表達式。如a[3] , b[i] , c[6*i];
  • 數組元素下標從0開始;長度爲n的數組合法下標取值範圍: 0 —>n-1; 如int a[]=newint[3];可引用的數組元素爲a[0]a[1]a[2]
數組元素的長度

每個數組都有一個屬性length指明它的長度,例如: a.length 指明數組a的長
度(元素個數)

  • 數組一旦初始化,其長度是不可變的
數組元素的默認初始化值

數組是引用類型,它的元素相當於類的成員變量,因此數組一經
分配空間,其中的每個元素也被按照成員變量同樣的方式被隱式
初始化。

	public static void main(String argv[]){
		int a[]= new int[5];
		System.out.println(a[3]); //a[3]的默認值爲0
	}
  • 對於基本數據類型而言,默認初始化值各有不同
  • 對於引用數據類型而言,默認初始化值爲null(注意與0不同! )

在這裏插入圖片描述

數組的賦值和複製

賦值
int[] arr1,arr2;
arr1 = new int[]{2,3,5,7,9,15};
arr2 = arr1;
arr2[0]=1;
arr2[1]=1;
//此時arr1和arr2都變爲{1,1,5,7,9,15}

數組賦值只是將引用指向了數組對象,並沒有實現複製,改變了arr2,arr1也會發生改變。

複製
int[] arr1,arr2;
arr1 = new int[]{2,3,5,7,9,15};
arr2 = new int[arr1 .length];
for(int i = 0;i < arr2.length;i++){
	arr2[i]=arr1[i];
}
arr2[0]=1;
arr2[1]=1;
//此時arr1爲{2,3,5,7,9,15},arr2爲{1,1,5,7,9,15}

數組的反轉

方式一:

for(int i = 0;i < arr.length / 2;i++){
	int temp = arr[i] ;
	arr[i] = arr[arr.length - i - 1];
	arr[arr.length - i -1] = temp ;
}

方式二:

for(int i = 0,j = arr.length - 1;i < j;i++,j--){ 
	String temp = arr[i];
	arr[i] = arr[j] ;
	arr[j] = temp;
}

圖解數組的內存機制

Java的內存空間分配

Java程序爲了提高程序的效率,就對數據進行了不同空間的分配。具體的是劃分爲瞭如下5個內存空間:

  1. 棧:存放的是局部變量
  2. 堆:存放的是所有new出來的東西
  3. 方法區: (面向對象部分詳細講解)
  4. 本地方法區::(和系統相關)
  5. 寄存器::(CPU使用)
堆內存的特點
  • 每一個new出來的東西都有地址值
  • 每個變量都有默認值
    byte, short, int, long 0
    float, double. 0. 0
    char,\u0000’
    boolean. false
    引用類型null
  • 使用完畢就變成了垃圾,但是並沒有立即回收。會在垃圾回收器空閒的時候回收。

數組的內存

數組是一種引用內存,數組引用變量只是一個引用,數組元素和數組變量在內存裏是分開存放的。

實際的數組對象(即數組元素)被存放在堆內存(heap)中,數組的引用變量(即數組對象)被存儲在棧內存中。

在這裏插入圖片描述

內存解析

數組對象如果重新賦值,那麼數組對象重新指向新的實際數組的地址值。數去引用的舊數組變成垃圾,等待垃圾回收機制回收。具體分析如下圖:
在這裏插入圖片描述

代碼
	public static void main(String[] args) {
        //定義並靜態初始化數組
        int [] array1={1,2,3};
        //定義並動態初始化數組
        int []array2=new int[4];
        //輸出array2的長度
        System.out.println("array2的長度:"+array2.length);
        //循環輸出array1數組的元素
        for(int i=0;i<array1.length;i++){
            System.out.println(array1[i]);
        }
        System.out.println("---------------------------------");
        //循環輸出array2的數組元素
        for(int i=0;i<array2.length;i++){
            System.out.println(array2[i]);
        }
        array2=array1;
        //再次輸出array2的長度
        System.out.println("array2的長度"+array2.length);
    }

多維數組

Java 語言裏提供了支持多維數組的語法。如果說可以把一維數組當成幾何中的線性圖形,那麼二維數組就相當於是一個表格。

對於二維數組的理解,我們可以看成是一維數組array1又作爲另一個一維數組array2的元素而存在。其實, 從數組底層的運行機制來看,其實沒有多維數組。

二維數組的使用

格式一(動態初始化)
 int[][] arr = new int[3][2];

定義了名稱爲arr的二維數組
二維數組中有3個一維數組
每一個一維數組中有2個元素
一維數組的名稱分別爲arr[0], arr[1], arr[2]
給第一個一維數組1腳標位賦值爲78寫法是: arr[0][1] = 78;

格式二(動態初始化)
 int[][] arr = new int[3][];

二維數組中有3個一維數組。
每個一維數組都是默認初始化值null (注意:區別于格式1)
可以對這個三個一維數組分別進行初始化
arr[0] = new int[3]; arr[1] = new int[1]; arr[2] = new int[2];

注:
int[][]arr = new int[][3]; //非法

格式3(靜態初始化)
 int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};

定義一個名稱爲arr的二維數組,二維數組中有三個一維數組
每一個一維數組中具體元素也都已初始化
第一個一維數組 arr[0] = {3,8,2};
第二個一維數組 arr[1] = {2,7};
第三個一維數組 arr[2] = {9,0,1,6};
第三個一維數組的長度表示方式: arr[2].length;

  • 注意特殊寫法情況: int[] x,y[]; x是一維數組, y是二維數組。
  • Java中多維數組不必都是規則矩陣形式

二維數組的內存解析

public static void main(String[] args) {
        //1. 二維數組的聲明與初始化
        int[] arr = new int[]{1,2,3};
        //1.1 數組的靜態初始化:數組的初始化和數組元素的賦值操作同時進行
        int[][] id = new int[][] {{10,12},{14,16},{18,20}};
        //1.2 數組的動態初始化:數組的初始化和數組元素的賦值操作分開進行
        String[][] names = new String[5][3];
        //1.3 錯誤的寫法:不能將動態初始化與靜態初始化同時進行
        //char[][] = new char[5][3]{{'k','l'},{'y','u'}};錯誤的寫法
        //String[][] arr2 = new String[][4];
        
       //正確:
         int[] arr4[] = new int[][]{{10,12},{14,16},{18,20}};
         int[] arr5[] = {{10,12},{14,16},{18,20}};
        
        二位數組元素默認的初始化
        int[][] arr7 = new int[4][3];
        sysout(arr7[0])    //[@15bffst  地址值
        sysout(arr7[0][0]); //0 數組中數據類型的默認值
    
    }

在這裏插入圖片描述

Arrays工具類的使用

java.util.Arrays類即爲操作數組的工具類, 包含了用來操作數組(比
如排序和搜索) 的各種方法。

方法 備註
boolean equals(int[] a,int[] b) 判斷兩個數組是否相等。
String toString(int[] a) 輸出數組信息。
void fill(int[] a,int val) 將指定值填充到數組之中。
void sort(int[] a) 對數組進行排序。
int binarySearch(int[] a,int key) 對排序後的數組進行二分法檢索指定的值。

數組常見的異常

1.數組腳標越界異常(ArrayIndexOutOfBoundsException)

int[] arr = new int[2];
System.out.println(arr[2]);
System.out.println(arr[-1]);

訪問到了數組中的不存在的腳標時發生。

2.空指針異常(NullPointerException)

int[] arr = null;
System.out.println(arr[0]);

arr引用沒有指向實體,卻在操作實體中的元素時。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章