網(wǎng)站首頁動畫效果怎么弄推廣廣告
1、方法的概念和使用
1.1、什么是方法
方法(method)是程序中最小的執(zhí)行單元,類似于 C語言中的函數(shù),方法存在的意義:
- 是能夠模塊化的組織代碼(當代碼規(guī)模比較復(fù)雜的時候).
- 做到代碼被重復(fù)使用, 一份代碼可以在多個位置使用.
- 讓代碼更好理解更簡單.
- 直接調(diào)用現(xiàn)有方法開發(fā), 不必重復(fù)造輪子
注意:
- 方法必須先創(chuàng)建才可以使用,該過程稱為方法定義。
- 方法創(chuàng)建后并不是直接可以運行的,需要手動使用后,才執(zhí)行,該過程稱為方法調(diào)用
1.2、方法的定義
方法定義語法格式:
//方法定義
修飾符 返回值類型 方法名稱(參數(shù)類型1 形參1,參數(shù)類型2 形參2...){方法體代碼;[return 返回值];
}
類比main
函數(shù):public static void main(String[] args)
,其中void
是返回值類型;main
是方法名稱;String[] args
是參數(shù)類型和形參。
例子:
判斷閏年
1、能被4整除且不能被100整除的是閏年
2、能被400整除的是閏年
//判斷閏年方法
public static boolean isLeapYear(int year){if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){System.out.println(year+"是閏年");return true;}else{System.out.println(year+"不是閏年");return false;}
}
【注意事項】
- 修飾符:現(xiàn)階段直接使用
public static
固定搭配 - 返回值類型:如果方法有返回值,返回值類型必須要與返回的實體類型一致,如果沒有返回值,必須寫成
void
- 方法名字:采用小駝峰命名(首字母小寫,后續(xù)單詞首字母大寫)
- 參數(shù)列表:如果方法沒有參數(shù),
()
中什么都不寫,如果有參數(shù),需指定參數(shù)類型,多個參數(shù)之間使用逗號隔開 - 方法體:方法內(nèi)部要執(zhí)行的語句
- 在java當中,方法必須寫在類當中
- 在java當中,方法不能嵌套定義
- 在java當中,沒有方法聲明一說,方法只有先定義,才能調(diào)用。
- 方法的返回值類型是
void
時,可以省略return
;但是也可以寫,后面不加數(shù)據(jù)即可。
1.3、方法調(diào)用的執(zhí)行過程
方法的調(diào)用方式:
方法名(參數(shù)1,參數(shù)2,...);
調(diào)用過程:
- 調(diào)用方法
方法名(參數(shù)1,參數(shù)2,...);
- 傳遞參數(shù),注意參數(shù)的數(shù)量與類型必須與方法定義中的設(shè)置相匹配,否則程序?qū)箦e 。
- 找到方法地址
- 執(zhí)行被調(diào)方法的方法體
- 被調(diào)方法結(jié)束返回
- 回到主調(diào)方法繼續(xù)往下執(zhí)行。
例子:
public class Test01 {//判斷閏年方法public static boolean isLeapYear(int year){if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){System.out.println(year+"是閏年");return true;}else{System.out.println(year+"不是閏年");return false;}}public static void main(String[] args) {Scanner scan = new Scanner(System.in);System.out.println("請輸入年份:");int year = scan.nextInt();//方法的調(diào)用boolean ret = isLeapYear(year);}
}
在其他函數(shù)中去調(diào)用方法時的參數(shù)稱為實際參數(shù)(實參)即上述main函數(shù)中的boolean ret = isLeapYear(year);
這句代碼中year
,在方法定義中的參數(shù)稱為形式參數(shù)(形參)即上述isLeapYear
方法中的public static boolean isLeapYear(int year)
這句代碼的year
。
【注意事項】
- 定義方法的時候,不會執(zhí)行方法的代碼,只有調(diào)用時才會執(zhí)行。
- 一個方法可以多次調(diào)用。
例子:
計算 1! + 2! + 3! + 4! + 5!
//求階乘
public static int fac(int n){if(n == 1 || n == 0){return 1;}else {return n * fac(n - 1);}
}
public static void main(String[] args) {//計算 1! + 2! + 3! + 4! + 5!int sum = 0;for (int i = 1; i <= 5 ; i++) {sum += fac(i);}System.out.println(sum);
}
1.4、實參和形參的關(guān)系
- 形參:方法定義中的參數(shù)
- 等同于規(guī)定了變量定義的格式。
- 實參:方法調(diào)用中的參數(shù)
- 等同于使用變量或常量。
形參只是拿到了實參的值,形參的名字可以隨意取,對方法沒有影響;形參和實參的名字也可以相同。
方法放在main
前或者后都可以,與 C語言不同(自頂向下編譯)。在 java 中,實參的值永遠都是賦值到形參中,形參和實參本質(zhì)是兩個實體。
例子1:
//交換兩個數(shù)值
public static void swap(int x, int y){int tmp =x;x = y;y = tmp;
}public static void main(String[] args) {int a = 10,b = 20;System.out.println("交換前:"+ a +" "+b);swap(a,b);System.out.println("交換后:"+ a +" "+b);
}
【運行結(jié)果】
交換前:10 20
交換后:10 20
【分析】
實參a
和b
是main
方法中的兩個變量,其分配的內(nèi)存空間在main
方法的棧(一塊特殊的內(nèi)存空間)中,而形參x
和y
是swap
方法中的兩個變量,x
和y
的內(nèi)存空間在swap
方法運行時的棧中,因此:實參a
和b
與 形參x
和y
是兩個沒有任何關(guān)聯(lián)性的變量,在swap
方法調(diào)用時,只是將實參a
和b
中的值拷貝了一份傳遞給了形參x
和y
,因此對形參x
和y
操作不會對實參a
和b
產(chǎn)生任何影響。
對于基本數(shù)據(jù)類型來說,形參相當于實參的拷貝,即傳值調(diào)用。
【解決辦法】
傳引用數(shù)據(jù)類型參數(shù)(如數(shù)組)因為引用數(shù)據(jù)類型在內(nèi)存中存儲的是地址值,指向在堆內(nèi)存中申請的一片內(nèi)存。
例子2:
public class TestMethod {public static void main(String[] args) {int[] arr = {10, 20};swap(arr);System.out.println("arr[0] = " + arr[0] + " arr[1] = " + arr[1]);}public static void swap(int[] arr) {int tmp = arr[0];arr[0] = arr[1];arr[1] = tmp;}
}// 運行結(jié)果
arr[0] = 20 arr[1] = 10
2、方法重載
2.1、為什么需要方法重載
首先,如果我們定義一個函數(shù)add()
實現(xiàn)兩個整數(shù)的相加,但后面如果想實現(xiàn)兩個浮點數(shù)的相加時,會因為參數(shù)的數(shù)據(jù)類型的不同導致報錯。
例子1:
只有我們重新寫一個方法,定義形參的數(shù)據(jù)類型是double
的方法才能實現(xiàn),但是這種形式的缺點就是需要命名不同的方法名,并且容易記憶混亂,那么可以直接使用同一個方法名嗎?由此引出方法重載。
2.2、方法重載概念
在日常交流中,一個詞語如果有多重含義,比如:喜歡,情侶之間說喜歡與子女對父母說喜歡,這個詞語的含義是不同的,這個時候我們可以認為該詞語含義被重載,具體代表什么意思就需要結(jié)合具體的場景。
java 中,如果多個方法的方法名相同,參數(shù)列表不同,與返回值無關(guān),則稱這幾種方法被重載了。
其中參數(shù)列表不同包括:個數(shù)不同,類型不同,順序不同。
例子:
之后調(diào)用該方法時通過 IDEA 會有提示,根據(jù)需要傳入的實參類型,選擇相應(yīng)的方法。
【注意事項】
- 方法名必須相同。
- 參數(shù)列表必須不同(參數(shù)個數(shù)/參數(shù)類型/參數(shù)的次序)。
- 多個方法必須定義在同一個類中。
- 與返回值類型是否相同無關(guān)。
- 如果僅僅因為返回值類型不同,是不能構(gòu)成重載的。
- 編譯器在編譯代碼時,會對實參類型進行推演,根據(jù)推演的結(jié)果來確定調(diào)用哪個方法。
2.3、方法簽名(了解)
在同一個作用域中不能定義兩個相同名稱的標識符,但是在類中可以定義方法名相同的方法。
是因為有方法簽名的存在。
方法簽名即是:經(jīng)過編譯器編譯修改之后方法最終的名字。具體方式:方法全路徑名+參數(shù)列表+返回值類型,構(gòu)成方法完整的名字。每一個方法都有簽名。
將編寫的代碼經(jīng)過編譯后,會生成.class
文件,在該文件所在的目錄下打開命令行窗口,輸入javap -v 字節(jié)碼文件名
即可
例子:
public class TestMethod {public static int add(int x, int y){return x + y;}public static double add(double x, double y){return x + y;}public static void main(String[] args) {add(1,2);add(1.5, 2.5);}
}
生成的字節(jié)碼文件:
方法簽名中的一些特殊符號說明:
3、遞歸
3.1、遞歸的概念
一個方法在執(zhí)行過程中調(diào)用自身,就稱為“遞歸”。遞歸相當于數(shù)學的“數(shù)學歸納法”,有一個起始條件,然后有一個遞推公式。
遞歸條件:將原問題劃分成其子問題,子問題。
3.2、遞歸練習
按順序打印一個數(shù)字的每一位(例如 123打印出 1 2 3 )
public class Test03 {//按順序打印一個數(shù)字的每一位(例如 1234 打印出 1 2 3 4)public static void print(int n){if(n > 9){print(n / 10);}System.out.print(n % 10+" ");}public static void main(String[] args) {print(123);}
}
【分析】
遞歸求 1 + 2 + 3 + … + 10
//遞歸求 1 + 2 + 3 + ... + 10
public static int fac(int n){if(n == 1){return 1;}else{return n+fac(n-1);}
}
寫一個遞歸方法,輸入一個非負整數(shù),返回組成它的數(shù)字之和.
例如,輸入 1729, 則應(yīng)該返回1+7+2+9,它的和是19
public static int sum(int n){while(n > 9){return n % 10 + sum(n/10);}return n % 10;
}
求斐波那契數(shù)列第 n 項
第一項從 1 開始:1 1 2 3 5 8…
public static int fib(int n){if(n == 1 || n == 2){return 1;}else{return fib(n-1) + fib(n-2);}
}
非遞歸:
if(n == 1){return 1;
}
if(n == 2){return 1;
}
int n1 = 1;
int n2 = 1;
int n3 = 0;
while(n > 2){n3 = n1 + n2;n1 = n2;n2 = n3;n--;
}
return n3;
第 1 項從 0 開始 :0 1 1 2 3 5 8
public static int fib(int n){if(n == 1){return 0;}if(n == 2){return 1;}return fib(n-1)+fib(n-2);
}
非遞歸:
if(n == 1){return 0;
}
if(n == 2){return 1;
}
int n1 = 0;
int n2 = 1;
int n3 = 0;
while(n > 2){n3 = n1 + n2;n1 = n2;n2 = n3;n--;
}
return n3;
遞歸求解漢諾塔問題
有3根柱子,A,B,C;A柱上放N個盤子,上面小,下面大
問題:
把A柱上所有盤子挪到C柱上(可以借助B柱)
過程中:所有柱子上的盤子,也要下面大,上面小,且一次只能移動一個盤子。
// 定義一個方法用于解決漢諾塔問題
public static void hanoi(int n, char source, char auxiliary, char target){// 如果只有一個圓盤,直接將其從源柱移動到目標柱if (n == 1) {System.out.println("Move disk 1 from "+source+" to "+target);return;}// 先將 n - 1 個圓盤從源柱借助目標柱移動到輔助柱hanoi(n - 1, source, target, auxiliary);// 再將第 n 個圓盤從源柱移動到目標柱System.out.println("Move disk "+ n +" from "+source+" to "+target);// 最后將 n - 1 個圓盤從輔助柱借助源柱移動到目標柱hanoi(n - 1, auxiliary, source, target);
}
分析:
- 把
n-1
個盤子從源柱子借助目標柱子移動到輔助柱子。 - 把第
n
個盤子從源柱子移動到目標柱子。 - 把
n-1
個盤子從輔助柱子借助源柱子移動到目標柱子。
時間復(fù)雜度:O(2<sup>n</sup>)
如n=4時,
將上面 3 個盤子從源柱 A
借助目標柱 C
移動到輔助柱 B
:
將第 4 個盤子從源柱 A
移動到目標柱 C
:
將輔助柱 B
上的 3 個盤子借助源柱 A
移動到目標柱 C