1. 程式人生 > 實用技巧 >JavaSE第05篇:Java基礎語法之陣列、方法

JavaSE第05篇:Java基礎語法之陣列、方法

目錄

本篇我們將會學習Java基礎語法之陣列和方法。陣列,是一種基礎的資料結構,陣列可以讓我們通過一個變數管理一組資料;方法可以將一個功能封裝,在需要這個功能的地方,只需要呼叫方法即可,而不用再重複編寫冗餘的程式碼。接下來,我們將會詳細講解Java中的陣列、方法。

第一章:陣列

1.1-為什麼要學習陣列(瞭解)

需求:統計10個人每個人的薪資,並計算出10個人薪資的總和以及平均薪資?

此時,面臨這個需求,我們會怎麼做呢?

按照目前已經學過的知識,我們可能會這麼解決:

  1. 定義10個變數,存放10人的薪資
  2. 讓10個變數相加,計算總薪資
  3. 讓總薪資除以10,計算平均薪資

以上的解決方案,確實可以滿足我們的需求,程式碼如下:

package com.penglei666.com;

public class Test01 {
    public static void main(String[] args) {
        /*
        * 定義10個變數,存放10個人的薪資
        * */
        double salary1 = 10000;
        double salary2 = 13000;
        double salary3 = 15888;
        double salary4 = 12000;
        double salary5 = 11888;
        double salary6 = 15888;
        double salary7 = 10000;
        double salary8 = 13000;
        double salary9 = 12000;
        double salary10 = 11888;
        // 計算總薪資
        double sum = salary1 + salary2 + salary3 + salary4 + salary5 + salary6 + salary7 + salary8 + salary9 + salary10;
        // 計算平均薪資
        double avg = sum / 10;
        System.out.println("總薪資:" + sum);
        System.out.println("平均薪資:" + avg);

    }
}


但是我們可以發現,一些不好的現象:

  1. 變數定義太多,若是計算100個人的薪資,那豈不是要定義100個變數,那1000個人、10000個人更不用說了。
  2. 連續累加,計算重複。

以上這些不好的問題,根本的原因,就是變數定義太多,一個具體的薪資資料對應一個變數,導致操作複雜且臃腫。

如何解決以上的問題呢?我們當然要從根本上解決,想辦法實現,讓一個變數管理一組資料。

此時,我們就需要學習陣列。

1.2-什麼是陣列 (理解)

一個固定長度的資料容器,可以有序地存放同類型的資料

  • 固定長度,存放資料的個數。
  • 有序,容器中的每一個數據都有一個索引(編號),從左向右,索引從0開始。
  • 同類型的資料,容器中的存放的資料型別要一致。

1.3-陣列的定義格式(記憶)

格式1:

資料型別[] 陣列名

double[]salay;
int[]age;
char[]arr;

格式2:

資料型別 陣列名[]

double salay[];
int age[];
char arr[];

以上僅僅是定義了陣列的名稱,但是未賦值。

1.4-陣列的動態初始化(記憶)

什麼是動態初始化

陣列動態初始化就是只給定陣列的長度,由系統給出預設初始化值

  • double型別陣列,預設值0.0
  • int型別陣列,預設值是0
  • boolean型別陣列,預設值是false
  • char型別陣列,預設值是0.0
  • 物件型別陣列,預設值是null

動態初始化格式:

資料型別[] 陣列名 = new 資料型別[陣列長度];

資料型別 陣列名[] = new 資料型別[陣列長度];

double[]salary = new double[10];

=左邊:

  • double,表示陣列的型別
  • [],表示是一個數組
  • salary,表示陣列的名稱(變數名)

=右邊:

  • new,為陣列開闢記憶體空間

  • double,表示陣列的型別

  • [],表示是一個數組

  • 10,表示陣列的長度

1.5-訪問陣列元素(記憶)

訪問陣列元素(陣列中的資料),就是獲取陣列中的某一個位置的資料。

索引

每一個儲存到陣列的元素,都會自動的擁有一個編號,從0開始,向後逐一加1。

這個自動編號稱為陣列索引(index),可以通過陣列的索引訪問到陣列中的元素。

訪問陣列元素格式

陣列名[索引]

package com.penglei666.com;

public class Test02 {
    public static void main(String[] args) {
        double[]salary = new double[10];
        // 輸出陣列,輸出結果:[D@b684286
        System.out.println(salary);
        // 輸出陣列中索引為0的元素,double陣列中資料預設值是0.0
        System.out.println(salary[0]);
        System.out.println(salary[0]);
        System.out.println(salary[0]);
    }
}

1.6-記憶體分配 (理解)

記憶體

  • 記憶體是計算機中的重要原件,臨時儲存區域,作用是執行程式。

  • 我們編寫的程式是存放在硬碟中的,在硬碟中的程式是不會執行的。

  • 必須放進記憶體中才能執行,執行完畢後會清空記憶體。

  • Java虛擬機器要執行程式,必須要對記憶體進行空間的分配和管理。

Java中的記憶體分配

目前我們只需要記住兩個記憶體,分別是:棧記憶體堆記憶體

陣列在記憶體中的分配過程

public static void main(String[] args) {
    double[]salary = new double[10];
    // 輸出陣列,輸出結果:[D@b684286
    System.out.println(salary);
    // 輸出陣列中索引為0的元素,double陣列中資料預設值是0.0
    System.out.println(salary[0]);
    System.out.println(salary[1]);
    System.out.println(salary[2]);
}

執行過程:

  • ① 程式執行時,首先main方法,入棧執行。

  • ② main方法執行時,發現new關鍵字建立陣列,則會在堆記憶體中,為陣列開闢連續的空間,並設定預設值。

  • ③ 陣列開闢空間後,返回記憶體地址給陣列名稱,輸出陣列名稱,則輸出了記憶體地址。

  • ④ salary[0]表示,通過陣列記憶體地址,找到記憶體堆區中陣列空間中的索引為0的資料。

  • ⑤ salary[1]表示,通過陣列記憶體地址,找到記憶體堆區中陣列空間中的索引為1的資料。

  • ⑥ salary[2]表示,通過陣列記憶體地址,找到記憶體堆區中陣列空間中的索引為2的資料。

1.7-基本型別和引用型別的區別(理解)

基本資料型別和引用資料型別

基本資料型別,之前學習的資料型別,如:int、long、double、boolean等。

引用資料型別,現在學習的陣列就是引用資料型別

區別1:程式執行時,在記憶體中建立資料時,記憶體分配不同

  • 基本資料型別:
    • 會在棧記憶體開闢一塊空間存放資料。
  • 引用資料型別:
    • 會在堆記憶體開闢一塊空間存放資料具體資訊。
    • 同時也會在棧記憶體開闢一塊空間存放堆資料的引用(堆區的地址)

區別2:資料傳遞過程不同

  • 基本資料型別是值傳遞(資料在棧中會克隆一份新的,兩個資料互不影響)。
  • 引用資料型別是引用傳遞(資料的引用在棧中會克隆一份新的,但兩個引用指向堆區中的同一個具體資料)
package com.penglei666.com;

public class Test02 {
    public static void main(String[] args) {
        /*【基本數型別值傳遞】*/
        // 建立變數a,賦值為10
        int a = 10;
        // 把變數a,賦值給變數b
        int b = a;
        // 更改變數b的值
        b = 20;
        // 變數b發生改變,結果:20
        System.out.println(b);
        // 變數a沒有發生改變,結果:10
        System.out.println(a);

        /*【引用型別引用傳遞】*/
        // 建立陣列arr1
        int[]arr1 = new int[2];
        // 建立陣列arr2,並把arr1賦值給arr2
        int[]arr2 = arr1;
        // 輸出arr1索引為0的值,結果為0
        System.out.println(arr1[0]);
        // 輸出arr2索引為0的值,結果為0
        System.out.println(arr2[0]);
        // 更改arr1索引為0的值
        arr1[0] = 99;
        // 輸出arr1索引為0的值,結果為99
        System.out.println(arr1[0]);
        // 輸出arr2索引為0的值,結果為99
        System.out.println(arr2[0]);

    }
}

基本資料型別資料傳遞過程

引用資料型別資料傳遞過程

1.8-陣列靜態初始化(記憶)

什麼是靜態初始化

在建立陣列時,直接將元素確定

靜態初始化格式:

  • 完整版格式:資料型別[] 陣列名 = new 資料型別[]{元素1,元素2,...};
  • 簡化版格式:資料型別[] 陣列名 = {元素1,元素2,...};
public class ArrayDemo {
    public static void main(String[] args) {
        //定義陣列
        int[] arr = {1, 2, 3};

        //輸出陣列名
        System.out.println(arr);

        //輸出陣列中的元素
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

1.9-陣列中常見的問題(瞭解)

問題1:索引越界異常

public class ArrayDemo {
    public static void main(String[] args) {
        int[] arr = new int[3];
        System.out.println(arr[3]);  // 異常
    }
}

陣列長度為3,索引範圍是0~2,但是我們卻訪問了一個3的索引。

程式執行後,將會丟擲ArrayIndexOutOfBoundsException 陣列越界異常。在開發中,陣列的越界異常是不能出現的,一旦出現了,就必須要修改我們編寫的程式碼。

解決方式:將錯誤的索引修改為正確的索引範圍即可!

問題2:空指標異常

public class ArrayDemo {
    public static void main(String[] args) {
        int[] arr = new int[3];

        //把null賦值給陣列,變數將不會執行任何有效物件。
        arr = null;
        System.out.println(arr[0]);
    }
}

arr = null 這行程式碼,意味著變數arr將不會在儲存陣列的記憶體地址,也就不允許再運算元組了,因此執行的時候會丟擲 NullPointerException 空指標異常。

解決方式:給陣列一個真正的堆記憶體空間引用即可!

1.10-陣列遍歷(重點)

陣列遍歷:就是將陣列中的每個元素分別獲取出來,就是遍歷。遍歷也是陣列操作中的基石。

public class ArrayTest01 {
	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4, 5 };
		System.out.println(arr[0]);
		System.out.println(arr[1]);
		System.out.println(arr[2]);
		System.out.println(arr[3]);
		System.out.println(arr[4]);
	}
}

以上程式碼是可以將陣列中每個元素全部遍歷出來,但是如果陣列元素非常多,這種寫法肯定不行,因此我們需要改造成迴圈的寫法。陣列的索引是 0 到 length-1 ,可以作為迴圈的條件出現。

  • 獲取陣列的長度:陣列名.length
public class ArrayTest01 {
    public static void main(String[] args) {
        //定義陣列
        int[] arr = {11, 22, 33, 44, 55};

        //使用通用的遍歷格式
        for(int x=0; x<arr.length; x++) {
            System.out.println(arr[x]);
        }
    }
}

1.12-陣列應用(重點)

需求:統計10個人的薪資,計算總薪資、平均薪資和最大薪資。

package com.penglei666.com;

public class Test03 {
    public static void main(String[] args) {
        // 建立陣列,並靜態初始化10個人的薪資
        double[]salary={12000,10000,13000,15000,14000,18000,10000,13000,15000,14000};
        // 建立變數sum,表示總薪資,初始化為0
        double sum = 0;
        // 建立變數avg,表示平均薪資,初始化為0
        double avg = 0;
        // 建立變數maxValue,表示最高薪資,初始化陣列索引0為最大值,最終誰是最大值,需要比較
        double maxValue = salary[0];
        // 迴圈遍歷每一個人的薪資
        for(int i = 0; i < salary.length; i++) {
            // 取出每一個人的薪資,累計到變數sum中
            sum+=salary[i];
            // 從索引1開始,和maxValue比較,比maxValue值大,就把誰賦值給maxValue
            if(i>0) {
                if(salary[i]>maxValue) {
                    maxValue = salary[i];
                }
            }
        }
        // 計算平均薪資
        avg = sum / salary.length-1;
        // 輸出總薪資
        System.out.println("薪資總和:" + sum);
        System.out.println("平均薪資:" + avg);
        System.out.println("最大薪資:" + maxValue);
    }
}

第二章:方法

2.1-為什麼要學習方法(理解)

需求

一個簡單的需求:有三個陣列如下:

int[]arrA = {22,11,44,33};
int[]arrB = {1,4,5,2,3};
int[]arrC = {20,33,29,18};

分別計算並輸出陣列中最大值。

分析

按照現學的知識,我們可能會這麼做:

  • 計算陣列arrA中的最大值
    1. 定義一個變數如:maxA,表示最大值,初始化為arrA[0]
    2. 迴圈遍歷陣列arrA,取出每一個值與maxA比較,若遍歷的元素大於maxA,則把當前元素賦值給maxA
    3. 遍歷結束後,maxA的值就代表最大值。
  • 計算陣列arrB中的最大值
    1. 思路同上
  • 計算陣列arrC中的最大值
    1. 思路同上
package com.penglei666.com;

public class Test04 {
    public static void main(String[] args) {
        /*定義三個陣列*/
        int[]arrA = {22,11,44,33};
        int[]arrB = {1,4,5,2,3};
        int[]arrC = {20,33,29,18};
        /*求陣列arrA中的最大值*/
        int maxA = arrA[0];
        for(int i = 1; i < arrA.length; i++){
            if(arrA[i]>maxA) {
                maxA = arrA[i];
            }
        }
        System.out.println("最大值:" + maxA);
        /*求陣列arrB中的最大值*/
        int maxB = arrB[0];
        for(int i = 1; i < arrB.length; i++){
            if(arrB[i]>maxB) {
                maxB = arrB[i];
            }
        }
        System.out.println("最大值:" + maxB);
        /*求陣列arrC中的最大值*/
        int maxC = arrC[0];
        for(int i = 1; i < arrC.length; i++){
            if(arrC[i]>maxC) {
                maxC = arrC[i];
            }
        }
        System.out.println("最大值:" + maxC);
    }
}

問題及解決方案

以上解決方案確實可以實現功能。但是存在這樣的問題:

  • 程式碼重複

此處的重複,是邏輯重複,若有更多的陣列需要計算,豈不是要寫更多一樣的邏輯程式碼,這樣程式碼會越來越臃腫且難以維護,若需求更變,要求最小值,豈不是要逐一修改。

那如何去解決呢?以上是邏輯重複,變化的僅僅是陣列,所以我們想辦法這樣解決問題:

  1. 把邏輯封裝一個模板。
  2. 向這個模板中傳入一個數組,就會得到一個最大值的結果,傳入一個數組,就會得到一個最大值的結果。

這個模板只需要定義一次,在需要的時候呼叫這個模板即可。

在程式設計中,確實提供了這樣的語法來實現把邏輯封裝成一個模組,這個語法機制就是方法

2.2-什麼是方法 (瞭解)

方法,在程式設計中也叫函式,也表示功能。

方法,可以將一段程式碼封裝在一個程式碼塊中,代表一個功能

注意:

  • 方法必須先建立才可以使用,該過程成為方法定義
  • 方法建立後並不是直接可以執行的,需要手動使用後,才執行,該過程成為方法呼叫

2.3-無引數方法定義和呼叫(記憶)

定義格式

public static void 方法名 (   ) {
	// 方法體;
}

示例如下:

public class Test05 {
    public static void main(String[] args) {
        
    }

    /**
     * 定義一個求陣列中最大值的方法
     */
    public static void getMax(){
        int[]arr = {22,11,44,33};
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

注意:方法定義不能巢狀,比如:不能再main方法中定義getMax。

呼叫方法

呼叫格式:方法名()

示例如下:

public class Test05 {
    public static void main(String[] args) {
        // 呼叫getMax方法
        getMax();
    }

    /**
     * 定義一個求陣列中最大值的方法
     */
    public static void getMax(){
        int[]arr = {22,11,44,33};
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

為什麼在main方法中呼叫,因為main方法是程式執行的入口。

每個方法在被呼叫執行的時候,都會進入棧記憶體,並且擁有自己獨立的記憶體空間,方法內部程式碼呼叫完畢之後,會從棧記憶體中彈棧消失。

2.4-帶引數方法定義和呼叫(記憶)

定義格式

引數:由資料型別和變數名組成 , 資料型別 變數名

方法定義時,引數中的資料型別與變數名都不能缺少,缺少任意一個程式將報錯,多個引數之間用,分割

public static void 方法名 (引數1) {
	方法體;
}

public static void 方法名 (引數1, 引數2, 引數3...) {
	方法體;
}

示例:

public static void isEvenNumber(int number){
    ...
}
public static void getMax(int num1, int num2){
    ...
}

案例改進:

public class Test05 {
    public static void main(String[] args) {

    }

    /**
     * 求一個數組中的最大值
     * @param arr 表示一個數組
     */
    public static void getMax(int[]arr){
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

呼叫

方法名(引數);

方法名(引數1,引數2);

方法呼叫時,要傳入實際的資料。

public class Test05 {
    public static void main(String[] args) {
        /*定義三個陣列*/
        int[]arrA = {22,11,44,33};
        int[]arrB = {1,4,5,2,3};
        int[]arrC = {20,33,29,18};
        /*求陣列arrA中的最大值*/
        getMax(arrA);
        /*求陣列arrB中的最大值*/
        getMax(arrB);
        /*求陣列arrC中的最大值*/
        getMax(arrC);
    }

    /**
     * 求一個數組中的最大值
     * @param arr 表示一個數組
     */
    public static void getMax(int[]arr){
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

方法呼叫時,引數的數量與型別必須與方法定義中的設定相匹配,否則程式將報錯 。

2.5-形參和實參 (理解)

形參:在定義方法時,小括號中定義的變數。

實參:在方法呼叫時,小括號中傳入的實際的資料。

2.6-帶返回值方法的定義和呼叫(記憶)

需求:計算三個陣列中三個最大值的和。

此時,我們需要呼叫完方法後,得到結果,這個結果不是輸出,而是用來和其他最大值相加。

如何得到結果呢?

可以使用方法返回值,就是一個方法呼叫完畢後,可以通過一個變數接收方法的返回值。

帶返回值的方法定義:

public static 資料型別 方法名 ( 引數 ) { 
	return 資料 ;
}

方法定義時return後面的返回值與方法定義上的資料型別要匹配,否則程式將報錯。

範例:

// 檢測一個數字是否是偶數
public static boolean isEvenNumber( int number ) {           
	boolean isEven = number%2==0;
	return isEven;
}
// 求兩個不同數字的最大值
public static int getMax( int a, int b ) {
	if(a>b) {
		return a;
	}else {
		return b;
	}
}

呼叫

呼叫方式:返回值型別 變數名 = 方法名(實參)

示例:

public class Test06 {
    public static void main(String[] args) {
        // 檢測8是否是偶數
        boolean isEven = isEvenNumber(8);
        System.out.println(isEven);  // isEven是true
        // 求10和100哪個數字比較大
        int max = getMax(10,100);
        System.out.println(max);     // max是100
    }

    /**
     * 檢測要給數字是否是偶數
     * @param number ,傳入一個數字
     * @return 返回布林值,true表示是偶數,false表示不是偶數
     */
    public static boolean isEvenNumber( int number ) {
        boolean isEven = number%2==0;
        return isEven;
    }

    /**
     * 求兩個數字中的最大值
     * @param a 一個數字
     * @param b 另一個數字
     * @return  返回較大的int型別數字
     */
    public static int getMax( int a, int b ) {
        if(a>b) {
            return a;
        }else {
            return b;
        }
    }
}

案例程式碼:

public class Test05 {
    public static void main(String[] args) {
        /*定義三個陣列*/
        int[]arrA = {22,11,44,33};
        int[]arrB = {1,4,5,2,3};
        int[]arrC = {20,33,29,18};
        /*求陣列arrA中的最大值*/
        int maxA = getMax(arrA);
        /*求陣列arrB中的最大值*/
        int maxB =getMax(arrB);
        /*求陣列arrC中的最大值*/
        int maxC = getMax(arrC);
        // 求最大值的和
        System.out.println(maxA + maxB + maxC);  // 82
    }

    /**
     * 求一個數組中的最大值
     * @param arr 表示一個數組
     * @return 返回一個int型別的數字,表示最大值
     */
    public static int getMax(int[]arr){
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        return max;
    }
}

2.7-方法注意事項(瞭解)

① 方法不能巢狀定義

public class MethodDemo {
    public static void main(String[] args) {

    }

    public static void methodOne() {
		public static void methodTwo() {
       		// 這裡會引發編譯錯誤!!!
    	}
    }
}

② void表示無返回值,可以省略return,也可以單獨的書寫return,後面不加資料

public class MethodDemo {
    public static void main(String[] args) {

    }
    public static void methodTwo() {
        //return 100; 編譯錯誤,因為沒有具體返回值型別
        return;	
        //System.out.println(100); return語句後面不能跟資料或程式碼
    }
}

2.8-方法通用格式(記憶)

通用格式

public static 返回值型別 方法名(引數) {
   方法體; 
   return 資料 ;
}
  • public static ,修飾符,目前先記住這個格式

  • 返回值型別,方法操作完畢之後返回的資料的資料型別,如果方法操作完畢,沒有資料返回,這裡寫void,而且方法體中一般不寫return

  • 方法名,呼叫方法時候使用的標識,定義規則和變數名一樣。

  • 引數,由資料型別和變數名組成,多個引數之間用逗號隔開。

  • 方法體,完成功能的程式碼塊

  • return,如果方法操作完畢,有資料返回,用於把資料返回給呼叫者

如何定義方法

  • 明確返回值型別:主要是明確方法操作完畢之後是否有資料返回,如果沒有,寫void;如果有,寫對應的資料型別。
  • 明確引數:主要是明確引數的型別和數量

如何呼叫方法

void型別的方法,直接呼叫即可。

非void型別的方法,推薦用變數接收呼叫。

2.9-方法的過載(理解)

在Java程式中,可以定義的多個·重名引數列表不同(引數的個數或型別不同)的方法。這種現象叫做方法的過載。

public static void fn(int num1,int num2){
     System.out.print(num1 + num2);                        
}
// 定義有參有返回值方法
public static int fn(int num1,int num2,int num3){
  return num1 + num2 + num3;                        
}

注意:方法的過載與方法的返回值沒有關係

錯誤示例:以下不是方法過載,與返回值沒有關係。

public static int fn(int num1,int num2){
	
}
public static void fn(int num1,int num2){
	
}

第三章:IDEA 安裝下載教程

連結:https://pan.baidu.com/s/1fuZucWizXdLLfhBNu97Bbg
提取碼:bfbc