Java程序的方法設計

Java程序的方法設計

本文關鍵字:Java、方法定義、方法設計、方法調用、方法重載

一、方法的定義

我們在學習Java編程以後接觸到的第一個程序就是"Hello World”,在這當中涉及到兩個主要的結構:類和main方法,當時我們只是說明了main方法是程序的入口,那麼當我們想要自己定義一個方法時應該如何下手呢?

1. 概念與作用

首先我們要明確方法的概念和作用,從名稱上來說,方法也可以被稱爲函數,是用來解決同一類的問題的。從代碼的結構上來說,定義方法可以減少重複的代碼,也能使得整個程序結構更加清爽。

  • 假如我們需要計算兩個數的加和
public class Test{
    public static void main(String[] args){
        // 定義兩個變量,so easy
        int a = 10,b = 5;
        int c = a + b;
        System.out.println(c);// 15
    }
}
  • 如果我們需要多次反覆執行同一個邏輯,那麼就會產生很多相同的代碼
public class Test{
    public static void main(String[] args){
        int a = 10,b = 5;
        int c = 20,d = 10;
        // 可以看到,雖然變量名稱不同,但是計算的邏輯是相同的
        // 如果某一段代碼反覆出現,我們可以考慮將他提取出來變成一個方法
        int e = a + b;
        System.out.println(e);// 15
        int f = c + d;
        System.out.println(f);// 30
        int g = e + f;
        System.out.println(g);// 45
    }
}
  • 定義方法後調用
public class Test{
    public static void main(String[] args){
        int a = 10,b = 5;
        int c = 20,d = 10;
        // 原有的代碼邏輯將轉變爲方法的調用
        plus(a,b);// 執行方法時輸出:15
        plus(c,d);// 執行方法時輸出:30
        plus(e,f);// 執行方法時輸出:45
    }
    // 定義一個用於計算兩個數加和的方法,計算後輸出結果
    public static void plus(int m,int n){
        int result = m + n;
        System.out.println(result);
    }
}

從以上的例子我們可以看到:

  • 從結構上來說,方法就是由多行代碼所組成的集合
  • 從使用的角度來看,定義方法的目的是抽取出通用的部分,可以減少重複代碼的出現
  • 從最終的效果來看,多行代碼的執行轉化爲了方法的調用

2. 定義的格式

如果我們想定義一個方法,那就需要先了解定義方法的結構,按照次序分別爲:

  • 修飾符:對方法進行相關的限定,出現在返回值類型之前
    • 權限修飾符:一般我們會將權限修飾符寫在方法定義的最前面,它指明瞭這個方法都可以在什麼地方被調用,最開始都聲明爲public即可
    • 其他修飾符:可以修飾方法的關鍵詞還有static,final等,會在其他文章中逐一介紹,修飾符的先後順序沒有嚴格要求
  • 返回值類型:指明瞭方法執行後是否需要進行返回,以及相應的類型
  • 方法名:指定方法的名稱,方法被調用時使用,在同一類中同名方法將構成重載
  • 參數列表:聲明調用方法時需要傳入的參數,可以爲空,也可以多個
  • 方法體:方法被調用時所執行的代碼,是方法的核心部分,需要與方法的返回值類型呼應

3. 方法的簽名

方法名稱和參數列表構成了方法簽名,方法簽名可以唯一的確定一個方法,並且對鑑別是否構成重載十分有用。

public class Test{
    // 方法簽名:main(String[] args)
    public static void main(String[] args){
        int a = 10,b = 5;
        int c = plus(a,b);
    }
    // 方法簽名:plus(int m,int n)
    public static int plus(int m,int n){
        return m + n;
    }
}

4. 方法的註釋

在定義一個方法後,我們在使用編譯器調用時只能夠查看到方法簽名及返回值類型,我們希望對於相近或重載的方法進一步進行描述,有利於使用者對方法的區分。
對方法添加註釋時需要使用文檔註釋,稱之爲javadoc,這樣在進行調用時就可以顯示方法的相關信息,對於方法的註釋主要包括以下幾個部分:

  • 方法作用描述:描述方法的作用
  • 方法參數描述:@param,解釋每個參數代表的含義
  • 返回類型描述:@return,解釋返回值代表的含義

在編譯器中可以輸入/**快速生成一個方法的模板,效果如下:

public class Test{
    /**
     * 計算兩個數的加和
     * @param a 第一個加數
     * @param b 第二個加數
     * @return 兩個數的加和
     */
    public int plus(int a,int b){
        return a + b;
    }
}

二、方法的設計

明確了方法的定義結構之後,我們需要做的就是希望在解決實際問題時知道如何去定義一個方法,並且有一個清晰的思路。

1. 方法設計的思路

筆者認爲一個方法的設計其實更像是整個編程思想的縮影,無論是完成一個複雜的功能還是某一個方法的定義都可以按照下面三個步驟來進行:

  • What I want?

要定義一個方法,就要先明確:我需要完成怎樣一個功能,用於解決一個什麼樣的問題?明確了之後我們就可以知道這個方法的用途,進而確定方法的名稱、返回值類型、調用訪問的權限、是否有其他修飾符。

  • What I need?

接下來要我們要根據方法的用途,考慮這個方法執行時都需要什麼,是否需要傳入一些參數?於是我們可以確定參數列表的部分了。

  • How to do?

在明確了方法要解決的問題以及所需要的參數之後,我們就可以分析方法中用該編寫什麼樣的代碼來解決問題,也就是最後確定方法體的部分,用上傳遞進來的參數,最後返回應該返回的變量或進行打印輸出。

2. 方法名稱的確定

方法名稱的定義比較容易,因爲自定義的程度較高,沒有什麼強制性的規則,只要滿足標識符的規定就可以了。一般來說,方法的命名也需要做到見名知意,以小寫字母開頭,如果遇到多個單詞首字母大寫,可以是字母和數字的組合。

3. 參數列表的確定

參數列表的確定主要就是考慮調用方法時需要傳入的參數的類型,可以爲空,也可以爲一個至多個,分別需要聲明類型和名稱。

  • 聲明的類型用於限制調用方法時傳入參數的類型
  • 聲明的名稱用於代表傳遞進來的參數

除此之外,我們還需要了解一下各種參數類型之間的差別:

  • 基本數據類型:對於基本數據類型,我們可以認爲是值的傳遞,即:這是一個值拷貝之後,複製的過程,我們在方法中如果對參數的值進行修改,也不會改變原有的值。
public class Test{
    public static void main(String[] args){
        int a = 10;
        test(a);// 進行方法的調用,方法中對值進行了修改
        System.out.println(a);// 結果爲10
    }
    public static void test(int n){
        System.out.println(n);// 接收到值,結果爲10
        n = 100;// 修改n的值,不會影響傳入的參數a的值
        System.out.println(n);// 結果爲100
    }
}
  • 引用類型:包括數組在內的引用類型,也就是除了基本數據類型以外的其他類型,在進行傳遞時發生的是引用傳遞,也就是說參數接收到的是一個引用,相當於多了一個變量指向了同一個位置,這樣在方法中進行的修改直接會作用在對象實例上。
public class Test{
    public static void main(String[] args){
        int[] a = {1,2,3};
        test(a);// 進行方法的調用,方法中對數組a進行了修改
        for(int i = 0;i < a.length;i++){
            System.out.println(n);// 結果爲10,20,30
        }
    }
    public static void test(int[] n){
        for(int i = 0;i < n.length;i++){
            System.out.println(n[i]);// 接收數組的引用,結果爲:1,2,3
        }
        for(int i = 0;i < n.length;i++){
            n[i] = n[i] * 10;// 修改數組的值,每個元素變爲原來的10倍
        }
        // 對於修改對象的屬性值同理,直接作用在對象本身
    }
}

Java程序的方法設計

  • 可變參數:可變參數與數組類似,但是卻有所不同,允許調用時以羅列的方式將參數傳進來
    • 可變參數又叫不定參數,從字面解釋就是:有的時候我不確定參數到底有幾個,但是又不想每次都構建一個數組,這個時候就可以使用不定參數
    • 可變參數在一個方法的定義中只能出現一個
    • 可變參數只能出現在參數列表的最後一個位置
    • 不建議使用Object類型作爲可變參數類型,將在方法重載時說明
    • 聲明格式:參數類型... 參數名稱,如:int... nums
public class Test{
    public static void main(String[] args){
        int a = 1;
        int b = 2;
        int c = 3;
        test(null);// 調用成功,此時參數爲null
        test();// 調用成功,此時參數個數爲0
        test(a);// 調用成功,傳入1個參數
        test(a,b);// 調用成功,傳入2個參數
        test(new int[]{a,b,c});// 調用成功,也可構建成數組後傳入
    }
    public static void test(int... nums){
        // 將nums當成數組一樣使用即可,可以通過判斷數組長度確定傳入參數的個數
        // 前提是傳入的參數不爲null,否則會出現空指針異常
        if(nums == null){
            System.out.println("傳入的參數爲null");
        }else{
            System.out.println("傳入的參數個數爲:" + nums.length);
        }
    }
}

4. 返回類型的確定

如何確定一個方法是否需要有返回值呢?在上述的方法中,在返回值類型的部分我們使用的都是void關鍵字,代表此方法返回值爲空,或無需返回。其實,對於一個方法是否需要返回這不是一個語法問題,而是取決於我們使用者的需要,我們來討論一下這兩種情況。

  • void:代表方法執行後不需要指定返回值,也就是不需要使用return關鍵字,只需要完成方法的邏輯,輸出某些信息,或者通過引用修改對象的某些屬性。
  • 其他類型
    • 返回值類型只能指定一種,但可以是數組類型
    • 如果聲明瞭返回值類型,那麼必須配合return關鍵字一同使用
    • return在一般情況下只能出現在方法的最後一行,作爲方法的結束
    • 在選擇結構中,也可能不會出現在最後一行的位置,可以根據需要提前結束某一個方法,但是必須保證選擇結構對應的所有情況都有相應的返回值
    • return後只能跟一個變量的名稱或表達式,變量或表達式結果的類型必須和返回值類型相同
    • 如果需要同時返回多個變量的值,可以使用數組
    • 如果需要同時返回多種類型的變量,可以將返回值類型聲明爲:Object[]
public class Test{
    public static void main(String[] args){
        // 需要實現如下邏輯:計算兩個數的加和,並將得到的結果變爲10倍後輸出
        int a = 1,b = 2;
        // 在進行方法調用後,我們必須想辦法先得到兩個數計算加和的結果,再繼續下一步
        int c = plus(a,b);
        // 使用對應類型的變量(c)接收返回結果,然後繼續下一步操作
        int result = c * 10;
        System.out.println(result);
    }
    public static int plus(int a,int b){
        return a + b;
    }
}

5. 方法內容的確定

能夠根據需要熟練並快速的寫出方法體中的內容這是一個長期訓練和鍛鍊的過程,有的時候我們並不是不知道如何使用方法這種結構,而是給出的問題根本沒有任何的思路。在這裏筆者將給大家一些建議,因爲舉再多的例子也無法在短時間內對大家有實質性的幫助。
其實程序本身只是我們一種邏輯思維表達,而且計算機真的很笨,所有的步驟都需要你一步一步去告訴他,比如你想寫一個判斷素數的程序,不要指望你定義一個變量i,然後使用選擇結構在判斷條件中寫上:if(i == 素數){}計算機就能明白,你首先要讓計算機明白什麼是素數,或者符合什麼樣的條件的數是素數。基本上所有的問題都可以轉換爲一個數學問題,或者是具有步驟的邏輯問題,特別是我們要讓計算機幫助我們去完成一項操作或功能的時候,你必須告訴它明確的步驟,以及遇到各種情況要如何處理,畢竟大佬是這麼說的:
Java程序的方法設計
很多同學看到這句話的第一反應可能是:我信你個鬼!你個xx頭子壞得很!但是仔細想想其實很有道理,特別是對於初學者,我們在學習編程時一定要嘗試去理解計算機是如何工作的,如何教會它來幫助我們解決問題。
那麼筆者的建議可以概括爲以下幾點:

  • 不要着急開始一個方法的編寫
  • 首先理清問題的解決步驟
  • 如果可能,對每一個步驟進行細化,分析可能出現的情況,給出解決的辦法
  • 結合所學的語法知識,將每一個步驟翻譯爲相應的結構或代碼
  • 如果沒有解決問題,重複以上步驟
  • 經歷幾次之後你就可以完全在大腦中完成這幾個步驟,順暢的寫出方法的內容

三、方法的調用

當一個方法被定義以後,只有被調用了纔會被執行,否則也是沒有意義的。

1. 方法調用的格式

根據上面的例子,我想對於方法的調用方式大家已經掌握了。沒錯,很簡單:方法名稱 + 傳入參數。有關於參數的寫法上需要作出一點說明,在進行方法定義時,我們需要聲明參數的類型,而在調用方法,傳入參數時,我們需要做的僅僅是匹配,不要再次聲明參數的類型,而只需要保證傳入的參數與定義的類型相匹配就好,可以傳入一個具體的值,也可以是聲明賦值後的變量,還是那句話:類型匹配就好。

2. 方法的執行過程

方法的執行過程其實比較簡單,具體的包含嵌套調用的結構我們將在後面的文章中說明。方法的執行過程其實用到的了一個最基本的結構:順序結構。如果一段代碼在執行的過程中遇到了方法調用,那麼一定會進入到方法中,將方法中的代碼全部執行完畢,再返回到方法的調用處,繼續執行後面的代碼。
那麼這裏也給大家解釋一下初學者的問題:你說方法中定義的return是返回的意思,那到底返回到哪去了?什麼時候返回的?
解釋這個問題可以用一句話概括:返回到了調用該方法的位置。首先,只有一個方法被調用以後,纔會執行其中的代碼,纔會輪到return語句的執行,那麼return之後去哪了呢?自然是返回到調用這個方法的位置繼續執行,這個時候,整個方法的調用語句就代表了這個方法的返回值,我們直接使用對應類型的變量接收就可以了。

public class Test{
    public static void main(String[] args){
        // 需要實現如下邏輯:計算兩個數的加和,並將得到的結果變爲10倍後輸出
        int a = 1,b = 2;// 代碼執行步驟:1
        // 代碼執行步驟:2,進行方法的調用
        int c = plus(a,b);// 代碼執行步驟:4,進行返回值的賦值
        int result = c * 10;// 代碼執行步驟:5
        System.out.println(result);// 代碼執行步驟:6
    }
    public static int plus(int a,int b){
        return a + b;// 代碼執行步驟:3
    }
}

3. 調用的注意事項

  • static修飾符

static修飾符有很多作用,我們這裏只討論它用在方法上時,對方法的調用產生怎樣的影響。由於main方法是程序的入口,那麼它必須使用static聲明,即:不需要實例化對象即可直接執行。那麼由於main方法是static修飾的,那麼它直接調用的方法必須也是由靜態(static)修飾的。

  • 接收返回值

具有返回值的方法在調用後,是不是一定要對返回值進行接收呢?當然不是必須的,如果不接收,方法的值也會正常返回,只不過隨即被丟棄了而已。接收時將方法調用語句看成一個整體,直接用對應類型的變量賦值接收即可。

四、方法的重載

<span id="jump"></span>

1. 重載的概念

重載指的是在一個類中,可以定義多個同名的方法,區別在於參數列表不同。對於重載的概念還是很好理解的,無非是描述了一種現象,在一個類中存在了很多名字相同的方法,大家需要掌握的就是如何定義才符合重載的規則,以及重載有什麼用?

  • 方法名稱相同,參數列表不同

不要看這個概念簡單,還是有很多同學在此翻車。方法名稱相同很好理解,完全一致的才叫做相同,這裏對大小寫敏感。另外一個概念是:參數列表不同,大家一定要注意,參數列表相同與否,是靠參數類型以及排列順序來決定的,與參數名稱無關。因爲參數列表中聲明的參數名稱只是傳入參數的一個代表,並不具備什麼具體的區分意義。

public class Test{
    // 求兩個整數和的方法:plus
    public int plus(int a,int b){
        return a + b;
    }
    // 參數列表相同,不構成重載,不能在類中同時存在
    public int plus(int c,int d){
        return c + d;
    }
    // 參數列表不同,構成重載
    public double plus(double a,double b){
        return a + b;
    }
    // 參數列表不同,構成重載,但是不定參數容易構成調用的歧義,不推薦
    public int plus(int... a){
        return 0;
    }
    // 參數列表相同,方法名稱不同,不構成重載,可以在類中同時存在
    public int Plus(int a,int b){
        return a + b;
    }
}
  • 方法重載有什麼用?

在很多時候,我們使用方法完成一個功能或邏輯,存在很多種情況,有些情況來自於代碼邏輯處理的過程中,也有些情況是要對不同的參數類型做出不同的操作。這個時候我們就可以利用重載的特點,用相同的方法名代表我們要處理的邏輯是類似的,然後在參數列表中聲明不同的參數類型,這樣就可以避免我們在方法中再繁雜的寫各種參數個數的判斷,參數類型的判斷,更加利於維護。同時,使用相同的方法類型,也使得使用者在調用時變得十分方便,不需要在同一功能上記憶各種不同的方法名稱,同時又能很好的解決問題。

2. 重載方法的調用

對於重載方法的調用,由於方法名稱相同,jvm主要就是根據傳入的參數類型來進行區分,效果如下:

public class Test{
    public static void main(String[] args){
        int a = 1,b = 2;
        int c = plus(a,b);// 調用plus(int a,int b)
        double m = 1.0,n = 2.0;
        double d = plus(m,n);// 調用plus(double a,double b)
    }
    // 求兩個整數和的方法:plus
    public static int plus(int a,int b){
        return a + b;
    }
    // 方法名相同,參數列表不同,構成重載
    public static double plus(double a,double b){
        return a + b;
    }
}

從上面的例子我們可以看到,在執行方法調用時主要是通過參數類型來進行區分的。但是當方法中出現不定參數時要尤爲注意:

public class Test{
    public static void main(String[] args){
        int a = 1,b = 2,c = 3;
        int d = plus(a);// 編譯失敗,與plus(int... a)和plus(int a,int... b)都匹配
        int e = plus(a,b);// 編譯成功,調用plus(int a,int b)
        int f = plus(a,b,c);// 編譯失敗,與plus(int... a)和plus(int a,int... b)都匹配
        int g = plus(new int[]{a,b});// 編譯成功,調用plus(int... a)
        int h = plus(a,new int[]{b,c});// 編譯成功,調用plus(int a,int... b)
    }
    // 求兩個整數和的方法:plus
    public static int plus(int a,int b){
        return a + b;
    }
    // 方法名稱相同,參數列表不同,構成重載,但是不定參數容易構成調用的歧義,不推薦
    public int plus(int... a){
        return 0;
    }
    // 方法名稱相同,參數列表不同,構成重載,但是不定參數容易構成調用的歧義,不推薦
    public int plus(int a,int... b){
        return 0;
    }
}

從以上的例子我們可以看到,如果重載方法中出現了不定參數,那麼在調用時很可能出現歧義,依然要通過手動構建數組的方式來解決,所以在進行方法重載時應該儘量避免出現不定參數,當不定參數是Object類型時,歧義問題就會更加嚴重

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