JavaSE學習筆記(四)——Java中的方法
一、Java中的方法
需求:求整數10和整數3的乘積,然後在求整數2000和整數300的乘積。
public class MethodTest01 { public static void main(String[] args){ int i = 10; int j = 3; int k = i * j; System.out.println("i * j = " + k); int l = 2000; int m = 300; int n = l * m; System.out.println("l * m =" + n); } } |
功能已經實現,但是存在的問題是,兩段程式碼完成的功能相同,資料的型別也相同。只是具體的資料不同。並且程式碼重複使用了兩次,雖然實現了功能,但缺點是相同功能的程式碼不能實現重用。所以在
1.1方法的定義
方法就是一段程式碼片段,可以完成特定的功能,並且可以重複利用。定義方法的語法格式如下。
[方法修飾列表] 返回值型別 方法名(方法形式引數列表){ 方法體; } |
方法修飾符:可以是public、protected、private、abstract、static、final和synchronized。注意:其中public、protected和private不能同時存在,只能是其中之一。
方法的返回值型別:可以是Java語言中的任何一種資料型別(基本資料型別和引用資料型別)。如果該方法執行結束之後,沒有任何返回值,那麼定義方法的時返回值型別為
方法名:合法的識別符號。
方法引數列表:定義方法時可以有引數,也可以沒有引數,如果有多個引數,引數之間要使用逗號進行分隔。
定義一個方法實現上面的需求。
public class MethodTest02 { public static void main(String[] args){ // 呼叫static修飾的靜態方法需要使用類名.的方式 // 直接呼叫方法並傳入需要乘積的引數 MethodTest02.method(10, 3); MethodTest02.method(2000, 300); } // static修飾的方法是靜態方法 public static void method(int i,int j){ int product = i * j; System.out.println("i * j = " + product); } } |
定義方法。
public class MethodTest03 { public static void main(String[] args){ // 呼叫方法,靜態方法直接使用類名.的方式進行呼叫 MethodTest03.method01(); // 呼叫方法時同時傳遞引數給方法 MethodTest03.method02("張三"); // 呼叫有返回值的方法 int product = MethodTest03.method03(20, 30); System.out.println("product = " + product); } // 定義方法 // public 公共的,外面的類可以呼叫 // static 方法是靜態的 // void 沒有返回值 // method01 方法名 // 方法沒有引數 public static void method01(){ System.out.println("Hello Java"); } // 方法帶有一個String型別的引數 // 引數name是區域性變數,作用域在方法體內 public static void method02(String name){ System.out.println(name); } // 方法有兩個int型別的引數 // 方法有返回值,返回值型別為int型別 public static int method03(int i,int j){ int product = i * j; // 方法有返回值,必須有return語句,並且返回值的型別與方法定義的型別 // 相同,否則編譯不能通過 return product; // return 語句後面不能存在其他語句,否則編譯不能通過 // System.out.println("product = " + product); } } |
1.2方法的呼叫
靜態方法的呼叫原則。在同一個類中,呼叫靜態方法可以使用類名.的方式進行呼叫,也可以直接使用方法名進行呼叫。
public class MethodTest04 { public static void main(String[] args){ // 在同一個類中,可以直接使用方法名呼叫靜態方法 method02(); // 也可以使用類名的方式呼叫靜態方法 MethodTest04.method02(); // 不在同一個類中的靜態方法必須使用類名.的方式進價呼叫 A.method03(); } public void method01(){ method02(); MethodTest04.method02(); } public static void method02(){ System.out.println("Hello Java"); } } class A{ // 在A類中定義的靜態方法 public static void method03(){ System.out.println("A method03()"); } } |
呼叫帶引數的靜態方法,需要傳遞相應型別的引數。通常情況下呼叫有返回值的方法就是要取得返回值,返回值變數的型別必須與方法返回值的型別相同。在方法中,return語句執行則方法結束,執行流程放回到方法呼叫處。
public class MethodTest05 { public static void main(String[] args){ // 呼叫有返回值的靜態方法 int success = method01(true); // 返回值型別是方法的返回值型別 // 引數的型別必須是方法定義的引數型別,並且順序相同 int product = method02(10,3); System.out.println("product: " + product); // 不在同一個類中,必須採用類名.的方式呼叫靜態方法 A.method03("張三"); } // 靜態方法 public static int method01(boolean b){ /* if(b){ return 1; }else{ return 0; } */ if(b){ return 1; } return 0; } // 靜態方法,返回值型別是int型,兩個引數。形式引數型別是int public static int method02(int i,int j){ // 返回值的型別必須是方法定義的返回值型別 return i / j; // return語句執行,方法結束,所以不能有語句在return後面,編譯不能通過 // System.out.println(i / j); } } class A{ // 定義的靜態方法 public static void method03(String name){ System.out.println("name: " + name); } } |
如何終止方法的執行,採用的方式是如果符合某種條件,使用return語句終止方法的執行。
public class MethodTest06 { public static void main(String[] args){ method01(11); method01(8); } // 靜態方法,沒有返回值,一個形式引數,型別是int public static void method01(int i){ // 如果引數值大於10終止方法執行 if(i > 10){ // return語句執行,方法結束 return; } for(;i <= 10;i++){ if(i == 5){ // break只是結束終止迴圈 break; } System.out.println("i = " + i); }
System.out.println("break後要執行的語句"); } } |
return語句的使用方式。
public class MethodTest07 { public static void main(String[] args){ // 靜態方法呼叫 method01(); String info = method02(); System.out.println(info); } public static void method01(){ // 方法沒有返回值,如果使用return,return後面不能存在語句 //return; // 編譯可以通過,雖然最後的語句不會輸出 if(true){ return; } System.out.println("HelloWord"); } public static String method02(){ // 如果方法有返回值,必須存在return語句,後面的值型別必須和返回型別 // 相同,並且return語句後面不能跟其他語句 //return "HelloWord"; // 這種方式可以, /* if(true){ return "HelloWord"; }else{ return "OK"; } */ // 這種方式可以 if(true){ return "HelloWord"; }
return "OK"; // 方法有返回值,return語句一定是最後一條語句,否則編譯不能通過 //System.out.println("HelloWord"); } } |
1.3方法的過載
需求:定義三個方法,分別是int型別、double型別和long型別實現乘積的方法,方法有返回值。
public class MethodTest08 { public static void main(String[] args){ int product1 = productInt(10,20); System.out.println(product1); double product2 = productDouble(10.11,93.23); System.out.println(product2); long product3 = productLong(10L,20L); System.out.println(product3); // 注意:型別從小容量到大容量,自動型別轉換 productInt(10,20); productDouble(10,20); productLong(10,20); } public static int productInt(int i1,int i2){ return i1 * i2; } public static double productDouble(double d1,double d2){ return d1 * d2; }
public static long productLong(long l1,long l2){
return l1 * l2; } } |
上面的程式碼實現了功能,但是存在的問題是每個方法的方法名稱不同,相同的是求兩個數值型別的值的乘積。另外,還需要記憶多個方法名,並且程式碼不是特別易讀。如果方法實現的功能相同,只是引數型別或者引數的數量不同,可以採用方法過載的方式,如下例子。
public class MethodTest09 { public static void main(String[] args){ int product1 = product(10,20); System.out.println(product1); double product2 = product(10.11,93.23); System.out.println(product2); long product3 = product(10L,20L); System.out.println(product3); } public static int product(int i1,int i2){ return i1 * i2; } public static double product(double d1,double d2){ return d1 * d2; }
public static long product(long l1,long l2){
return l1 * l2; } } |
修改後,三個方法的方法名稱相同,引數型別不同,返回值型別不同,但是呼叫時只需要傳入不同型別的引數,不需要指定呼叫哪個方法,系統會根據引數的型別自動呼叫相應的方法並將結果返回。並且不需要記憶更多的方法名稱。
方法過載的條件。
1.方法過載只出現在同一個類中
2.方法名相同
3.方法的引數型別,個數,順序至少有一個不同
4.方法的返回型別可以不同(不依靠返回型別來區分過載)
5.方法的修飾符可以不同,因為方法過載和修飾符沒有任何關係
public class MethodTest10 { public static void main(String[] args){ } // 方法過載必須在同一個類中 // 引數型別不同,是方法過載 public static void m1(int i1,int i2){} public static void m1(double d1,double d2){} // 引數數量不同,是方法過載 public static void m2(int i1){} public static void m2(double d1,double d2){} // 引數順序不同,是方法過載 public static void m3(int i1,double d1){} public static void m3(double d1,int i1){} // 引數型別相同,引數個數相同,不是方法過載,是方法重複 //public static void m4(int a){} //public static void m4(int b){} // 引數型別和個數相同,返回值型別不同,不是方法過載, // 方法過載和返回值型別無關 //public static int m5(int i){} //public static void m5(int i){} // 引數相同,訪問修飾符不同,不是方法過載,方法過載和訪問修飾符無關 //private static void m6(){} //public static void m6(){} } |
方法過載舉例。
public class MethodTest11 { public static void main(String[] args){ // sun提供的方法過載例子 System.out.println(10); System.out.println(23.2); System.out.println(true); System.out.println('A'); } } |
1.4類、方法、屬性(靜態變數)的關係
在一個類中,從類和成員的角度可分為靜態的和成員的部分。靜態的部分可分為靜態變數、靜態方法和靜態內部類等等。成員的部分可以分為成員變數、成員方法和成員內部類等等。注意:也就是說,在類體中只存在兩部分內容,一是屬性(成員的或靜態的),二是方法(成員方法或靜態方法)或內部類。那麼可以執行的程式碼只能存在與方法中,包括成員方法或靜態方法,所以,存在與方法中的程式碼是為了實現一個特定的功能,就像一個工廠生產特定的產品,方法的引數類似於工廠需要的生成原料,而方法的返回值相當於工廠生產出的產品。
public class MethodTest12 { // 類體 // 成員屬性 int i = 10; // 靜態變數 static String country = "中國"; // 成員方法 public void method01(int i){ // 方法體 // 可以執行的程式碼 // 將引數做一些特殊的處理 System.out.println(i); } // 靜態方法 public static int method02(int i1,int i2){ // 方法體 // 可以執行的程式碼 // 實現特定功能,並返回特定的結果 return i1 + i2; } public static void main(String[] args){ // 方法體 // 可以執行的程式碼 // 程式的執行入口方法 } } |
1.5呼叫方法的執行流程
1.5.1棧的概念
當通過Java命令執行一個程式時,會啟動一個JVM,Java虛擬機器程序,並建立程式執行環境,會建立程式執行的棧記憶體,下面的圖做了簡單的說明。
1.1.1程式的執行過程
下面通過一個程式說明程式的執行過程。
public class MethodTest13 { public static void main(String[] args){ // 呼叫method01()方法 method01(10); } // method01()方法呼叫method02()方法 public static void method01(int i){ method02(i); } // method02()方法呼叫method03()方法 public static void method02(int i){ method03(i); } public static void method03(int i){ System.out.println("i: " + i); } // method04()方法沒有被呼叫 public static void method04(int i){ System.out.println(i); } } |
main()方法呼叫method01()方法,method01()方法呼叫method02()方法,method02()方法呼叫method03()方法,在method03()方法中將引數輸出。下面通過一個圖說明程式的執行流程。
注意:當方法被呼叫時,才會在記憶體中為方法分配空間。如果只是定義了方法,但是沒有被呼叫,不會為方法在記憶體中分配空間。方法被呼叫時,Java虛擬機器會為方法在棧記憶體中為方法分配空間。方法被呼叫時會發生壓棧操作,當方法執行結束後會發生彈棧操作。
一、 遞迴
方法的遞迴呼叫就是方法自身呼叫自身。通常在樹形結構訪問時用到,如:目錄的遞迴檢索,又如許可權管理中許可權目錄數的訪問等等。下面的例子是遞迴的簡單演示。
public class RecursionTest01 { public static void main(String[] args){ // 呼叫method01()方法 method01(10); } // 方法method01() public static void method01(int i){ // 方法自己呼叫自己,無限呼叫下去沒有返回 method01(i); } } |
在上面的例子中,因為遞迴沒有結束的條件,所以每呼叫一次method01()方法,就會在記憶體中開闢空間,產生壓棧操作,但沒有出棧操作,不會釋放記憶體,會導致棧記憶體溢位錯誤!所以遞迴程式必須要有結束條件。
不使用遞迴計算1~n整數的和。
public class RecursionTest02 { public static void main(String[] args){ int sum = method01(10); System.out.println(sum); } public static int method01(int n){ int sum = 0; for(int i = 1;i <= n;i++){ sum += i; } return sum; } } |
使用遞迴實現1~n的求和。
public class RecursionTest03 { public static void main(String[] args){ int sum = sum(5); System.out.println(sum); } public static int sum(int n){ // 如果引數n等於1,直接返回 if(n == 1){ return 1; }else{ // 否則,將引數n減一作為引數呼叫自身,返回的值與引數n的和就是 // 最終的結果。 return n + sum(n - 1); } } } |
上面程式的執行流程:
練習:
1.採用遞迴的方式求1~n的偶數的和。
public class RecursionTest04 { public static void main(String[] args){ int sum = sum(5); System.out.println(sum); } public static int sum(int n){ if(n % 2 != 0){ n -= 1; } if(n == 2){ return 2; }else{ return n + sum(n - 2); } } } |
2.採用遞迴的方式求n!。
public class RecursionTest05 { public static void main(String[] args){ int sum = product(5); System.out.println(sum); } public static int product(int n){ if(n == 1){ return 1; }else{ return n * product(n - 1); } } } |
3.不採用遞迴的方式實現n!。
public class RecursionTest06 { public static void main(String[] args){ int sum = product(5); System.out.println(sum); } public static int product(int n){ int product = 1; for(int i = 1;i <= n;i++){ product *= i; } return product; } } |
轉載於:https://blog.51cto.com/dongkevin/1859921