本文關鍵字:Java、方法定義、方法設計、方法調用、方法重載java
咱們在學習Java編程之後接觸到的第一個程序就是"Hello World」,在這當中涉及到兩個主要的結構:類和main方法,當時咱們只是說明了main方法是程序的入口,那麼當咱們想要本身定義一個方法時應該如何下手呢?編程
首先咱們要明確方法的概念和做用,從名稱上來講,方法也能夠被稱爲函數,是用來解決同一類的問題的。從代碼的結構上來講,定義方法能夠減小重複的代碼,也能使得整個程序結構更加清爽。數組
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); } }
從以上的例子咱們能夠看到:jvm
若是咱們想定義一個方法,那就須要先了解定義方法的結構,按照次序分別爲:ide
方法名稱和參數列表構成了方法簽名,方法簽名能夠惟一的肯定一個方法,而且對鑑別是否構成重載十分有用。函數
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; } }
在定義一個方法後,咱們在使用編譯器調用時只可以查看到方法簽名及返回值類型,咱們但願對於相近或重載的方法進一步進行描述,有利於使用者對方法的區分。
對方法添加註釋時須要使用文檔註釋,稱之爲javadoc,這樣在進行調用時就能夠顯示方法的相關信息,對於方法的註釋主要包括如下幾個部分:學習
在編譯器中能夠輸入/**
快速生成一個方法的模板,效果以下:spa
public class Test{ /** * 計算兩個數的加和 * @param a 第一個加數 * @param b 第二個加數 * @return 兩個數的加和 */ public int plus(int a,int b){ return a + b; } }
明確了方法的定義結構以後,咱們須要作的就是但願在解決實際問題時知道如何去定義一個方法,而且有一個清晰的思路。翻譯
筆者認爲一個方法的設計其實更像是整個編程思想的縮影,不管是完成一個複雜的功能仍是某一個方法的定義均可以按照下面三個步驟來進行:設計
要定義一個方法,就要先明確:我須要完成怎樣一個功能,用於解決一個什麼樣的問題?明確了以後咱們就能夠知道這個方法的用途,進而肯定方法的名稱、返回值類型、調用訪問的權限、是否有其餘修飾符。
接下來要咱們要根據方法的用途,考慮這個方法執行時都須要什麼,是否須要傳入一些參數?因而咱們能夠肯定參數列表的部分了。
在明確了方法要解決的問題以及所須要的參數以後,咱們就能夠分析方法中用該編寫什麼樣的代碼來解決問題,也就是最後肯定方法體的部分,用上傳遞進來的參數,最後返回應該返回的變量或進行打印輸出。
方法名稱的定義比較容易,由於自定義的程度較高,沒有什麼強制性的規則,只要知足標識符的規定就能夠了。通常來講,方法的命名也須要作到見名知意,以小寫字母開頭,若是遇到多個單詞首字母大寫,能夠是字母和數字的組合。
參數列表的肯定主要就是考慮調用方法時須要傳入的參數的類型,能夠爲空,也能夠爲一個至多個,分別須要聲明類型和名稱。
除此以外,咱們還須要瞭解一下各類參數類型之間的差異:
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倍 } // 對於修改對象的屬性值同理,直接做用在對象自己 } }
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); } } }
如何肯定一個方法是否須要有返回值呢?在上述的方法中,在返回值類型的部分咱們使用的都是void關鍵字,表明此方法返回值爲空,或無需返回。其實,對於一個方法是否須要返回這不是一個語法問題,而是取決於咱們使用者的須要,咱們來討論一下這兩種狀況。
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; } }
可以根據須要熟練並快速的寫出方法體中的內容這是一個長期訓練和鍛鍊的過程,有的時候咱們並非不知道如何使用方法這種結構,而是給出的問題根本沒有任何的思路。在這裏筆者將給你們一些建議,由於舉再多的例子也沒法在短期內對你們有實質性的幫助。
其實程序自己只是咱們一種邏輯思惟表達,並且計算機真的很笨,全部的步驟都須要你一步一步去告訴他,好比你想寫一個判斷素數的程序,不要期望你定義一個變量i,而後使用選擇結構在判斷條件中寫上:if(i == 素數){}計算機就能明白,你首先要讓計算機明白什麼是素數,或者符合什麼樣的條件的數是素數。基本上全部的問題均可以轉換爲一個數學問題,或者是具備步驟的邏輯問題,特別是咱們要讓計算機幫助咱們去完成一項操做或功能的時候,你必須告訴它明確的步驟,以及遇到各類狀況要如何處理,畢竟大佬是這麼說的:
不少同窗看到這句話的第一反應多是:我信你個鬼!你個xx頭子壞得很!可是仔細想一想其實頗有道理,特別是對於初學者,咱們在學習編程時必定要嘗試去理解計算機是如何工做的,如何教會它來幫助咱們解決問題。
那麼筆者的建議能夠歸納爲如下幾點:
當一個方法被定義之後,只有被調用了纔會被執行,不然也是沒有意義的。
根據上面的例子,我想對於方法的調用方式你們已經掌握了。沒錯,很簡單:方法名稱 + 傳入參數。有關於參數的寫法上須要做出一點說明,在進行方法定義時,咱們須要聲明參數的類型,而在調用方法,傳入參數時,咱們須要作的僅僅是匹配,不要再次聲明參數的類型,而只須要保證傳入的參數與定義的類型相匹配就好,能夠傳入一個具體的值,也能夠是聲明賦值後的變量,仍是那句話:類型匹配就好。
方法的執行過程其實比較簡單,具體的包含嵌套調用的結構咱們將在後面的文章中說明。方法的執行過程其實用到的了一個最基本的結構:順序結構。若是一段代碼在執行的過程當中遇到了方法調用,那麼必定會進入到方法中,將方法中的代碼所有執行完畢,再返回到方法的調用處,繼續執行後面的代碼。
那麼這裏也給你們解釋一下初學者的問題:你說方法中定義的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 } }
static修飾符有不少做用,咱們這裏只討論它用在方法上時,對方法的調用產生怎樣的影響。因爲main方法是程序的入口,那麼它必須使用static聲明,即:不須要實例化對象便可直接執行。那麼因爲main方法是static修飾的,那麼它直接調用的方法必須也是由靜態(static)修飾的。
具備返回值的方法在調用後,是否是必定要對返回值進行接收呢?固然不是必須的,若是不接收,方法的值也會正常返回,只不過隨即被丟棄了而已。接收時將方法調用語句當作一個總體,直接用對應類型的變量賦值接收便可。
<span id="jump"></span>
重載指的是在一個類中,能夠定義多個同名的方法,區別在於參數列表不一樣。對於重載的概念仍是很好理解的,無非是描述了一種現象,在一個類中存在了不少名字相同的方法,你們須要掌握的就是如何定義才符合重載的規則,以及重載有什麼用?
不要看這個概念簡單,仍是有不少同窗在此翻車。方法名稱相同很好理解,徹底一致的才叫作相同,這裏對大小寫敏感。另一個概念是:參數列表不一樣,你們必定要注意,參數列表相同與否,是靠參數類型以及排列順序來決定的,與參數名稱無關。由於參數列表中聲明的參數名稱只是傳入參數的一個表明,並不具有什麼具體的區分意義。
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; } }
在不少時候,咱們使用方法完成一個功能或邏輯,存在不少種狀況,有些狀況來自於代碼邏輯處理的過程當中,也有些狀況是要對不一樣的參數類型作出不一樣的操做。這個時候咱們就能夠利用重載的特色,用相同的方法名錶明咱們要處理的邏輯是相似的,而後在參數列表中聲明不一樣的參數類型,這樣就能夠避免咱們在方法中再繁雜的寫各類參數個數的判斷,參數類型的判斷,更加利於維護。同時,使用相同的方法類型,也使得使用者在調用時變得十分方便,不須要在同一功能上記憶各類不一樣的方法名稱,同時又能很好的解決問題。
對於重載方法的調用,因爲方法名稱相同,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類型時,歧義問題就會更加嚴重。