1. 程式人生 > >Java語言基礎(三)---陣列

Java語言基礎(三)---陣列

Java語言基礎組成:關鍵字、識別符號、註釋、常量和變數、運算子、語句、函式、陣列

一. 陣列的定義:

  同一種類型資料的集合,其實陣列就是一個容器。
  運算時很多資料進行運算,先想到的不是運算,而是要把這些資料臨時儲存起來,以便於後期的運算。陣列就是儲存資料的一種方式。
【陣列的好處】:陣列能自動給存入元素進行編號,編號從0開始,方便操作這些元素。

【陣列的格式 1】:   元素型別[ ] 陣列名 = new 元素型別[元素個數或陣列長度];

  • 【元素型別】: 陣列中元素的資料型別

  • 【陣列名】: 是陣列型別的,陣列是單獨的資料型別

  • 【new 元素型別[元素個數或陣列長度]】:定義了真實存在的陣列,能存(陣列長度)個元素

  • 【new】: 用於在記憶體中產生一個容器實體。用來操作很多資料的地方,就用new來完成

  • 【例項】:定義一個可以儲存3個整數的容器(具體兩種方法定義長度為3的整型陣列)

      1. int[ ] x = new int[3];

      2. int x[ ] = new int[3];  // 建議採用第一種

【陣列的格式 2】:
(靜態儲存方式)
  元素型別[ ] 陣列名 = new 元素型別[ ]{ 元素1, 元素2, … };

  • 【 [ ] 】: 中括號中不要寫長度

  • 【何時使用?】: 當資料內容明確時使用

  • 【靜態儲存方式】: 通過 { } 的形式,標識出陣列中元素的內容。元素內容,個數都體現了,
              稱這種方式為靜態儲存方式。

  • 【例項】:定義一個可以儲存3個整數的容器

      1. int[ ] x = new int[ ]{3, 1, 6};

      2. int x[ ] = {3, 1, 6};  // 簡化形式


二. 陣列的記憶體分配及特點:

任何一個應用程式在執行時,都要在記憶體中開闢空間,cpu處理完A程式才會再處理B程式。
Java程式在執行時,需要在記憶體中分配5個空間:棧記憶體、堆記憶體、方法區、本地方法區、暫存器。

【例項 1】 int x = 3 在記憶體中的分配情況。

基本資料變數在記憶體中的分配情況

  • 【分析】:

    1. show函式執行完,show中的變數 x 就會在記憶體中消失。
    2. 如果show函式中有for迴圈語句:for (int x = 0; x < 5; x++) {}
      那麼同樣的,for迴圈執行完,for迴圈中的變數 x 就會在記憶體中消失。
  • 【棧的特點】:資料使用完畢,會自動釋放,變數會自動釋放。

  • 【記憶體為什麼劃分出這麼多空間,劃分這麼細?】:

     因為每一片記憶體空間中的資料處理方式不一樣,對於棧而言,資料使用完會自動釋放。

【例項 2】 分析在記憶體中的分配情況。

    int[] x = new int[3];
    x[0] = 59; 


引用變數在記憶體中的分配情況

  • 【分析】:

    1. 在棧記憶體中定義了x,凡是區域性變數都在棧記憶體中開闢空間。
      區域性變數指 :
        (1)定義在方法中的變數
        (2)定義在方法引數上的變數。
        (3)定義在for迴圈裡的變數等。

    2. new 出來的實體都在堆裡邊,堆裡邊存放的就是實體。實體為:陣列和物件。

    3. 【賦值】:將地址值賦值給變數x,賦值的不是陣列本身,而是陣列在記憶體中的地址。
              陣列並沒有真正地存放在x 中去,只存放了地址,它在引用陣列而已。

    4. 【指向】:變數x 有值了,稱為x 指向了這個陣列,或x 引用 了這個陣列。

【例項 3】 分析在記憶體中的分配情況。

    int[] x = new int[3]; 
    x = null;  


引用變數在記憶體中的分配情況

  • 【分析】:

    1. 只有引用資料型別,才能使用null。x = null =>表示 x 不再指向這個陣列,而且x 值為空。

    2. new int[3]在堆記憶體中沒有被任何人引用,就會被垃圾回收機制清除。(具體見堆特點3)
  • 【堆的特點】:

    1. 堆記憶體中的每個實體,都有一個存放位置(記憶體地址值),記憶體裡都是二進位制的地址值,用地址來標識資料存放的位置,那麼這個陣列在記憶體中存放的時候,總有一個起始位置,即所謂的陣列指向。

    2. 陣列一旦被定義,裡邊的元素都有值,堆記憶體中的實體用了封裝資料的,都有預設初始化值。
      int型陣列值:0
      double型陣列值:0.0
      float型陣列值:0.0f
      boolean型陣列值:false
      String型陣列值:null
      char型陣列值:’\u0000’ (相當於空格)

    3. 【垃圾回收機制】:陣列在堆記憶體中沒人使用了,當一個實體在堆記憶體中沒有任何引用所使用它的話,就視它為垃圾,或Java訓圾。這個垃圾不會立刻被記憶體清除掉,而是在不定時的時間內,啟動一個叫垃圾回收機制,將陣列實體在堆記憶體中清除。

      C++語言:由程式設計師手動地呼叫一個功能將記憶體中的資料清除。

      Java:程式設計師不用手動清除,只要這個物件或實體,在堆記憶體中已經變為垃圾,JVM會自動啟動垃圾回收機制,將堆記憶體中不再使用的實體清除。

    【例項 4】分析在記憶體中的分配情況。

     int[] x = new int[3]; 
     int[] y = x; 
     y[1] = 89;
     x = null;

/*【堆記憶體中有無垃圾?】
   => 沒有垃圾,x,y引用指向了同一個陣列物件,當x的值為空,不再指向陣列時,但是y仍指向陣列。
*/


引用變數在記憶體中的分配情況

【例項 5】分析在記憶體中的分配情況。

     int[] x = new int[3]; 
     int[] y = new int[3]; 
     y[1] = 89;
     x = null;

/**【堆記憶體中有無垃圾?】
   => 有垃圾。
      只要是new的,記憶體中就會開闢新的空間,y指向的是新的陣列。
      當x = null時,x之前指向的陣列,就無人指向,因而變為了垃圾。
*/


引用變數在記憶體中的分配情況

三. 陣列操作常見問題:

【例項 1】:陣列角標越界異常(ArrayIndexOutOfBoundsException )

    public static void main(String[] args) {
        int[] arr = {3, 1, 6};
        System.out.println(arr[2]);  //結果為:6
        System.out.println(arr[3]);  //[錯誤]
    }

【分析】:

  1. 【編譯不報錯,執行出錯】:在Java編譯時並不建立實體,在執行時建立陣列,Java編譯只是檢查語法錯誤。

  2. 【錯誤提示 ArrayIndexOutOfBoundsException : 3】:

    (1) [3]:陣列角標3越界。

    (2) [ArrayIndexOutOfBoundsException]:陣列角標越界異常。
       代表運算元組時,訪問到了陣列中不存在的角標。
       所以在訪問陣列角標的時候,注意陣列角標不能大於陣列的長度,因為陣列角標是從0開始的。

【例項 2】:空指標異常(ArrayIndexOutOfBoundsException )

    public static void main(String[] args) {
        int[] arr = {3, 1, 6};
        arr = null;
        System.out.println(arr[1]);  //[錯誤]
    }

【分析】:

  1. 【編譯不報錯,執行出錯】:在Java編譯時並不建立實體,在執行時建立陣列,Java編譯只是檢查語法錯誤。

  2. 【錯誤提示 NullPointerException】: 空指標異常。
     當沒有任何指向,值為null的情況,該引用還在用於操作實體,就會丟擲空指標異常。

四. 陣列常見操作:

1. 遍歷陣列

最為常見的獲取陣列中的元素,通常用遍歷,用for語句迴圈。【注】:角標最大值 = 陣列長度 - 1
陣列中有一個屬性可以直接獲取到陣列元素個數:陣列名稱.length

【注】:System.out.println(arr) 代表:把一個數組實體的引用給直接列印了。
    輸出結果為[[email protected]

  1. 【 [ 】:左中括號,表示陣列
  2. 【 I 】:陣列的元素型別為 int
  3. 【62bc184】:陣列的記憶體存放地址,地址是由雜湊演算法計算出來的雜湊值(十六進位制),
            因為十六進位制比較短所以採用十六進位制。

【例項 1】:求陣列和(【累加思想】:變數 + 迴圈)

    public static void main(String[] args) {
        int[] arr = {3, 1, 6};
        System.out.println("sum = " + getArraySum(arr));

    }

    /**
     * 功能:求出陣列的元素和
     * @param arr 陣列
     * @return 陣列元素和
     */
    public static int getArraySum(int[] arr)
    {
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum;
    }

【例項 2】:定義一個功能,用於列印陣列中的元素,元素間用逗號隔開。

    /**
     * 功能:用於列印陣列中的元素,元素間用逗號隔開
     * @param arr 陣列
     */
    public static void printArray(int[] arr)
    {
        for (int i = 0; i < arr.length; i++)
        {
            if (i != arr.length - 1) //元素間逗號隔開
            {
                System.out.print(arr[i] + ",");
            }
            else
            {
                System.out.println(arr[i]);
            }
        }
    }

【例項 3】:給定一個數組{5,1,6,4,2,8,9} 獲取陣列中的最大值,以及最小值。(只適用於數值型陣列)

    /**
     * 方法一:求max
     * 1. 定義變數max,初始化為陣列中仁義一個元素值即可,max = arr[0]
     * 2. 通過迴圈語句,對陣列進行遍歷
     * 3. 在變數中定義判斷條件,如果遍歷到的元素比變數中的元素大,就賦值給變數。
     * @param arr 陣列
     * @return 最大值
     */
    public static int getMax(int[] arr)
    {
        int max = arr[0];
        for (int i=1; i<arr.length; i++)
        {
            if(max < arr[i])
                max = arr[i];

        }

        return max;
    }


    /**
     * 方法二:求max
     * 1. 定義變數max,初始化為陣列中的任意一個角標,max = 0
     * 2. 通過迴圈語句,對陣列進行遍歷
     * 3. 在變數中定義判斷條件,如果遍歷到的元素比arr[max]中的元素大,就將元素角標賦值給變數。
     * @param arr 陣列
     * @return 最大值
     */
    /*public static int getMax(int[] arr)
    {
        int max = 0;
        for (int i = 1; i < arr.length; i++)
        {
            if(arr[max] < arr[i])
                max = i;
        }
        return arr[max];
    }*/

    //獲取double型別陣列的最大值,因為功能一致,所以定義相同函式名稱,以過載方式存在。
    public static double getMax(double[] arr)
    {
    }

    /**
     * 求min
     * @param arr 陣列
     * @return 最小值
     */
    public static int getMin(int[] arr)
    {
        int min = arr[0];
        for (int i=1; i<arr.length; i++)
        {
            if(min > arr[i])
                min = arr[i];

        }

        return min;
    }

2. 陣列排序

【排序的方法】:

  1. 氣泡排序 :相鄰兩個元素進行排序,如果符合條件則換位。
          特點:內迴圈結束一次,最值出現在最後位。

  2. 選擇排序:選擇固定位置的值,不斷地和其他元素進行比較,符合條件則換位,接著拿這個位置上的值進行比較。
         特點:內迴圈結束一次,最值出現在頭角標位置上。

  3. 插入排序:需要排序的陣列越有序,插入排序的效率越高。

  4. 希爾排序(是最快的排序,三層迴圈加上位運算):
          將需要排序的陣列分割成小的子陣列,對這個子陣列進行插入排序,排序後越來越接近有序的陣列。

  5. 快速排序

  6. 歸併排序

  7. 工具類Arrays:
      在Java中, 已經定義好了一種排序方式,是使用到了專門運算元組的工具類Arrays。
      Arrays有一個靜態方法sort可以對陣列進行排序。例如:Arrays.sort(arr);

【例項】 對給定陣列進行排序。{5,1,6,4,2,8,9}

(1)方法一:選擇排序

選擇排序

  • 【選擇排序】:選擇固定位置的值不斷和別人進行比較,交換位置後,依舊拿這個位子的值與別人比較。

  • 【選擇排序的特點】:內迴圈結束一次,最值出現在頭角標位置上,前面逐級進行排序

【例項】:程式碼體現

    public static void main(String[] args) {
        int[] arr = {5,1,6,4,2,8,9};
        System.out.println("-------------排序前-------------");
        printArray(arr);
        selectSort(arr); //選擇排序
        System.out.println("-------------排序後-------------");
        printArray(arr);
    }
    /**
     * 選擇排序
     * @param arr 陣列
     */
    public static void selectSort(int[] arr)
    {
        for (int i = 0; i < arr.length - 1; i++) {  //不需要遍歷最後一個角標,所以arr.length - 1

            for(int j = i + 1; j < arr.length; j++) //每個元素與後面進行比較,所以i + 1
            {
                if(arr[i] > arr[j])
                {
                    swap(arr, i, j); //兩數交換
                }
            }
        }
    }

    /**
     * 交換陣列中的兩個元素
     * @param arr 陣列
     * @param i 陣列角標i
     * @param j 陣列角標j
     */
    public static void swap(int[] arr, int i, int j)
    {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }

    /**
     * 列印陣列
     * @param arr 陣列
     */
    public static void printArray(int[] arr)
    {
        for (int i = 0; i < arr.length; i++) {
            if( i != arr.length -1)
            {
                System.out.print(arr[i] + ", ");
            }
            else
            {
                System.out.println(arr[i]);
            }
        }
    }

(2)方法二:氣泡排序

氣泡排序

  • 【氣泡排序】:相鄰的兩個元素進行排序,如果符合條件換位。

  • 【氣泡排序的特點】:

    1. 每次迴圈都是從0角標開始的。

    2. 第一圈最值出現在最後位。

    3. 第二次比較的特點:參與比較元素的長度 -1,逐漸減小。

【例項 1】:程式碼體現

    public static void main(String[] args) {
        int[] arr = {5,1,6,4,2,8,9};
        System.out.println("-------------排序前-------------");
        printArray(arr);
        bubbleSort(arr); //氣泡排序
        System.out.println("-------------排序後-------------");
        printArray(arr);
    }

    /**
     * 氣泡排序
     * @param arr 陣列
     */
    public static void bubbleSort(int[] arr)
    {
        for (int i = 0; i < arr.length - 1; i++) { //共迴圈比較arr.length - 1圈

            for (int j = 0; j < arr.length - i -1; j++) { //-i:讓每次比較的元素減少; -1:避免角標越界
                if(arr[j] > arr[j + 1])
                {
                    swap(arr, j, j + 1); //兩數交換,但是直接換位置,效能低,一圈中要換好幾次
                }
            }
        }
    }

    /**
     * 交換陣列中的兩個元素
     * @param arr 陣列
     * @param i 陣列角標i
     * @param j 陣列角標j
     */
    public static void swap(int[] arr, int i, int j)
    {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }

    /**
     * 列印陣列
     * @param arr 陣列
     */
    public static void printArray(int[] arr)
    {
        for (int i = 0; i < arr.length; i++) {
            if( i != arr.length -1)
            {
                System.out.print(arr[i] + ", ");
            }
            else
            {
                System.out.println(arr[i]);
            }
        }
    }

【例項 2】:氣泡排序的更優解(每一圈取出最值的角標,與最後的角標交換位置)

 如果兩個數需要換位置的話,先不要置換它們的位置,先把它們需要換位置的角標及元素記錄下來。
 在棧記憶體中,定義兩個變數,臨時記錄下來,全都比較完後,取最終需要換位置的值就可以了。
 把堆記憶體中頻繁地換位置,轉移到棧記憶體中。

    public static void main(String[] args) {
        int[] arr = {5,1,6,4,2,8,9};
        System.out.println("-------------排序前-------------");
        printArray(arr);
        bubbleSort(arr); //氣泡排序
        System.out.println("-------------排序後-------------");
        printArray(arr);
    }

    /**
     * 氣泡排序
     * @param arr 陣列
     */
    public static void bubbleSort(int[] arr)
    {
        for (int i = 0; i < arr.length - 1; i++) {

            int j = 0, max = 0; //max 記錄最大值的角標

            for (j = 1; j < arr.length - i; j++) {
                if(arr[j] > arr[max])
                {
                    max = j;
                }
            }
            if(j-1 != max) //如果max 角標不等於最後一個角標,兩數交換
            {
                swap(arr, j-1, max); //兩數交換
            }
        }
    }

    /**
     * 交換陣列中的兩個元素
     * @param arr 陣列
     * @param i 陣列角標i
     * @param j 陣列角標j
     */
    public static void swap(int[] arr, int i, int j)
    {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }

    /**
     * 列印陣列
     * @param arr 陣列
     */
    public static void printArray(int[] arr)
    {
        for (int i = 0; i < arr.length; i++) {
            if( i != arr.length -1)
            {
                System.out.print(arr[i] + ", ");
            }
            else
            {
                System.out.println(arr[i]);
            }
        }
    }

(3)方法三:直接插入排序

直接插入排序

  • 【插入排序】:將一個元素插入到已經排好序的陣列中去,從而得到一個新的陣列長度 + 1 的有序陣列。

  • 【插入排序的原理】:

    1. 假設陣列為一個有序陣列。

    2. 每次判斷陣列元素是否大於前一個數,如果小於的話,就往前遍歷陣列,將大於這個數的元素往後移,將這個數放入到具體位置,使陣列依然為有序陣列。

【例項】:程式碼體現(針對 insterSort 方法)

    /**
     * 直接插入排序
     * @param arr 陣列
     */
    public static void insterSort(int[] arr)
    {
        for (int i = 1; i < arr.length; i++) { //由角標1開始遍歷陣列
            if(arr[i] < arr[i-1]) //判斷陣列元素是否大於前一個數
            {
                int temp = arr[i], j;
                for (j = i - 1; j >= 0 && arr[j] > temp; j--) { //陣列往後移動
                    arr[j + 1] = arr[j];
                }
                arr[j + 1] = temp;
            }
        }
    }

(4)方法四:希爾排序

希爾排序

  • 【希爾排序】:把陣列進行分組,分割成若干個子序列,然後對子序列進行基本的插入排序。

  • 【希爾排序的原理】:

    1. 普通的插入排序:判斷間隔間隔為1
    2. 希爾排序:判斷間隔為space,並且間隔不斷縮小(除2操作)直到為0。

【例項 】:程式碼體現

    /**
     * 直接插入排序 + 希爾排序 + space取整
     * @param arr 陣列
     */
    public static void shellSort(int[] arr)
    {
        int space = arr.length;
        do
        {
            space >>= 1; // space = space/2;

            for (int i = space; i < arr.length; i++) {  //在直接排序的基礎上,將間隔1,改為space
                if(arr[i] < arr[i-space])
                {
                    int temp = arr[i], j;
                    for (j = i - space; j >= 0 && arr[j] > temp; j -= space) {
                        arr[j + space] = arr[j];
                    }
                    arr[j + space] = temp;
                }
            }

        }while(space > 0);
    }

3. 查詢陣列

陣列的查詢操作:在遍歷中進行判斷。

【查詢陣列的方法】:

  1. 簡單查詢:直接遍歷陣列進行匹配

  2. 折半查詢:折中找中間值,提高效率,但必須要保證該陣列是有序的陣列。

【例項】 定義功能,獲取key第一次出現在陣列中的位置,如果返回是-1,那麼代表該key在陣列中不存在
 (因為陣列下標不會存在-1)

  • (1) 方法一:從0角標遍歷陣列,進行查詢
    /**
     * 獲取key第一次出現在陣列中的位置
     * @param arr 陣列
     * @param key 匹配的資料
     * @return 陣列角標或-1,如果為-1,沒有找到key
     */
    public static int getIndex(int[] arr, int key)
    {
        for (int i = 0; i < arr.length; i++) {
            if(key == arr[i])
            {
                return i;
            }
        }
        return -1;
    }
  • (2) 方法二:折半查詢

折半查詢

    /**
     * 獲取key第一次出現在陣列中的位置
     * @param arr 陣列
     * @param key 匹配的數
     * @return 陣列角標或 -1
     */
    public static int halfSearch(int[] arr, int key)
    {
        int min = 0, max = arr.length - 1, mid;
        while(min <= max) //當min>max, 迴圈結束
        {
            mid = (min + max) >> 1; //獲得mid
            if(key > arr[mid])
            {
                min = mid + 1; 
            }
            else if(key < arr[mid])
            {
                max = mid - 1;
            }
            else
            {
                return mid;
            }
        }
        return -1;
    }

4. 插入元素

【例項】 有個有序的陣列,想要將一個元素插入到該陣列中,還要保證該陣列是有序的。

【思路】:通過折半的形式去查詢這個數,在陣列中的位置,如果這個數存在,在這個位置上把這個數插入,如果不存在,返回最小角標的值,就可以得到要插入的位置。

插入元素

    /**
     * 折半查詢,獲取插入元素的角標
     * @param arr 陣列
     * @param num 要插入的元素
     * @return 要插入元素的角標
     */
    public static int halfSearch(int[] arr, int num)
    {
        int min = 0, max = arr.length - 1, mid;
        while(min <= max)
        {
            mid = (min + max) >> 1;
            if(num > arr[mid])
            {
                min = mid + 1;
            }
            else if(num < arr[mid])
            {
                max = mid - 1;
            }
            else
            {
                return mid;
            }
        }
        return min;
    }

    /**
     * 將元素插入的相應的位置上,獲得新陣列
     * @param arr 陣列
     * @param index 要插入的角標
     * @param num 元素值
     * @return 新陣列
     */
    public static int[] getNewArray(int[] arr, int index, int num)
    {
        int[] rtnArr = new int[arr.length + 1];
        for (int i = 0; i < index; i++) {
            rtnArr[i] = arr[i];
        }
        rtnArr[index] = num;  //插入元素到指定位置
        for (int i = index; i < arr.length; i++) {
            rtnArr[i + 1] = arr[i];
        }
        return rtnArr;
    }

5. 進位制轉換

(1)十進位制轉換二進位制

    /**
     * 十進位制轉換二進位制
     * @param num 十進位制數
     * @return 二進位制(以字串形式返回)
     */
    public static String toBin(int num)
    {
        StringBuilder sb = new StringBuilder();
        while(num > 0)  //有侷限,負數無法求出
        {
            sb.append(num % 2 );
            num >>= 1;
        }
        return sb.reverse().toString();
    }

【查表法】:將所有的元素臨時儲存起來,建立對應關係,每一次&運算後的值作為索引去查建立好的表,就可以找到對應的元素(不用強制轉換了)

【利用查表法,更改上面的十進位制轉換】

    /**
     * 進製表
     */
    final static char[] digits = {
        '0' , '1' , '2' , '3' , '4' , '5' ,
        '6' , '7' , '8' , '9' , 'a' , 'b' ,
        'c' , 'd' , 'e' , 'f' 
    };

    /**
     * 十進位制轉換二進位制
     * @param num 十進位制數
     * @return 二進位制(以字串形式返回)
     */
    public static String toBin(int num)
    {
        StringBuilder sb = new StringBuilder();
        while(num != 0)
        {
            int temp = num & 1;
            sb.append(digits[temp]); //利用查表法,直接獲取對應值
            num >>>= 1;
        }
        return sb.reverse().toString();
    }

(2)十進位制轉換十六進位制

    /**
     * 進製表
     */
    final static char[] digits = {
        '0' , '1' , '2' , '3' , '4' , '5' ,
        '6' , '7' , '8' , '9' , 'a' , 'b' ,
        'c' , 'd' , 'e' , 'f' 
    };
    /**
     * 十進位制轉換二進位制
     * @param num 十進位制數
     * @return 二進位制(以字串形式返回)
     */
    public static String toHex(int num)
    {
        StringBuilder sb = new StringBuilder();
        while(num != 0)
        {
            int temp = num & 15;
            /*if(temp > 9)
            {
                sb.append((char)(temp-10 + 'a'));
            }
            else
            {
                sb.append(temp);
            }*/
            sb.append(digits[temp]);
            num >>>= 4;
        }
        return sb.reverse().toString();
    }

(3)十進位制轉換各種進位制(升級版)


    /**
     * 進製表
     */
    final static char[] digits = {
        '0' , '1' , '2' , '3' , '4' , '5' ,
        '6' , '7' , '8' , '9' , 'a' , 'b' ,
        'c' , 'd' , 'e' , 'f' 
    };

    public static void main(String[] args) {
        System.out.println(toBin(0));
        System.out.println(toHex(-60));
    }
    /**
     * 十進位制轉各種進位制數
     * @param num 十進位制數
     * @param base &運算的基數
     * @param offset >>>位移多少位
     * @return
     */
    public static String trans(int num, int base, int offset)
    {
        if(num == 0) // 不然當0的時候,沒有值
        {
            return "0";
        }
        StringBuilder sb = new StringBuilder();
        while(num != 0)
        {
            int temp = num & base;
            sb.append(digits[temp]);
            num >>>= offset;
        }
        return sb.reverse().toString();
    }

    /**
     * 十進位制轉換二進位制
     * @param num 十進位制數
     * @return 二進位制(以字串形式返回)
     */
    public static String toBin(int num)
    {
        return trans(num, 1, 1);
    }

    /**
     * 十進位制轉換十六進位制
     * @param num 十進位制數
     * @return 十六進位制(以字串形式返回)
     */
    public static String toHex(int num)
    {
        return trans(num, 15, 4);
    }

    /**
     * 十進位制轉換八進位制
     * @param num 十進位制數
     * @return 八進位制(以字串形式返回)
     */
    public static String toOctal(int num)
    {
        return trans(num, 7, 3);
    }

五. 二維陣列:

陣列中的陣列:往陣列中存放陣列,把陣列作為元素存入另一個數組中。

1. 二維陣列的定義:

【一維陣列】:   int[ ] arr = new int[3];

【二維陣列】:
 【陣列的格式 1】

  int[ ] arr = new int[3][4];

  • 【內容】: 定義了名稱為arr的二維陣列,二維陣列中有3個一維陣列,每個一維陣列中有4個元素。

  • 【new int[3][4]】:

      1. [3]:表示二維陣列的長度。

      2. [4]:表示二維陣列中一維陣列的長度。
 【陣列的格式 2】

  int[ ] arr = new int[3][ ];

  • 【內容】: 定義了名稱為arr的二維陣列,二維陣列中有3個一維陣列,但沒有指定一維陣列的元素。

  • 【new int[3][ ]】:

      1. [3]:表示二維陣列的長度。(一定要寫)

      2. [ ]:表示二維陣列中一維陣列沒有指定。即 arr[0] = null;

 【陣列的格式 3】(靜態儲存方式)

  int[ ] arr = { {3, 5, 7}, {2, 3, 5}, {6, 1, 8, 2} };

  • 資料之間有關係,分在一組中,產生二維陣列。

【一維陣列 與 二維陣列的小知識】:

  1. 一維陣列:int[ ] x = int x[ ]

  2. 二維陣列:int[ ][ ] x = int x[ ][ ] = int[ ] x[ ]

    【例項】int[ ] x, y[ ];  =>  int[ ] x, int[ ] y[ ];

       1. [ ] 定義在型別中,是隨型別走的,而型別的[ ],變數都有效
       2. [ ] 定義在變數後,是隨著變數走的,只有單個變數有效。

       (1)x[0] = y    [錯誤]
       (2)y[0] = x    [正確]
       (3)y[0][0] = x   [錯誤]
       (4)x[0][0] = y   [錯誤]
       (5)y[0][0] = x[0] [正確]
       (6)x = y      [錯誤]


2. 二維陣列的記憶體分配:

  • (1)【陣列的格式 1】 的記憶體分配


二維陣列的記憶體分配

【例項】列印二維陣列地址值

        int[][] arr = new int[3][4];
        System.out.println(arr);  //[[[email protected]
        System.out.println(arr[0]); //[[email protected]

        /*
        二維陣列的首地址:兩個左中括號
        一維陣列的首地址:一個左中括號
        */
  • (2)【陣列的格式 2】 的記憶體分配(不規則陣列)


二維陣列的記憶體分配

【分析】:

  1. int[ ][ ] arr = new int[3][ ];

    這個二維陣列中的一維陣列沒有初始化,用的是預設初始化,而陣列是引用資料型別,所以初始化值都為空,也就是這3個一維陣列變數(e.g. arr[0])沒有任何的小陣列指向。

  2. arr[0] = new int[3];

    對二維陣列中每一個小陣列進行手動初始化。初始化後,把陣列地址賦值給arr[0]。

【例項】列印二維陣列地址值

        int[][] arr = new int[3][];
        System.out.println(arr);  //[[[email protected]
        System.out.println(arr[0]); //null (一維陣列沒有指定)
        arr[0] = new int[3];
        arr[1] = new int[1];
        arr[2] = new int[2];
        arr[0][2] = 90;
        arr[1][1] = 89;
        arr[2][2] = 78;
        System.out.println(arr.length); //結果為:3
        System.out.println(arr[0].length); //結果為:3  列印二維陣列中第一個一維陣列的長度