一個 Java 方法是為了執(zhí)行某個操作的一些語句的組合。舉個例子來說,當(dāng)你調(diào)用 System.out.println 方法時,系統(tǒng)實際上會執(zhí)行很多語句才能在控制臺上輸出信息。
現(xiàn)在你將學(xué)習(xí)怎么創(chuàng)建你自己的方法,他們可以有返回值也可以沒有返回值,可以有參數(shù),也可以沒有參數(shù),重載方法要使用相同的方法名稱,并在程序設(shè)計中利用抽象的方法。
創(chuàng)建方法
我們用下面的例子來解釋方法的語法:
1
2
3
|
public static int funcName( int a, int b) { // body } |
在這里
- public static:修飾符
- int:返回值類型
- funcName:函數(shù)名稱
- a,b:形式參數(shù)
- int a,int b:參數(shù)列
方法也包含過程或函數(shù)。
- 過程:他們不返回值
- 函數(shù):他們返回值
方法的定義包含方法頭和方法體。如下所示:
1
2
3
|
modifier returnType nameOfMethod (Parameter List) { // method body } |
以上的語法包括
- modifier:他定義了方法的訪問類型,它是可選的。
- returnType:方法是可能返回一個值的。
- nameOfMethod:這是方法的名稱。方法簽名包括方法名稱和參數(shù)列表。
- Parameter List:參數(shù)列表,它是參數(shù)的次序,類型,以及參數(shù)個數(shù)的集合。這些都是可選的,當(dāng)然方法也可以沒有參數(shù)。
- 方法體:方法體定義了這個方法是用來做什么的。
示例
這是上面定義的方法max(),該方法接受兩個參數(shù)num1和num2返回兩者之間的最大值。
1
2
3
4
5
6
7
8
9
10
|
/** the snippet returns the minimum between two numbers */ public static int minFunction( int n1, int n2) { int min; if (n1 > n2) min = n2; else min = n1; return min; } |
方法調(diào)用
要想使用一個方法,該方法必須要被調(diào)用。方法調(diào)用有兩種方式,一種是有返回值的,一種是沒有返回值的。
調(diào)用方法很簡單,當(dāng)程序需要調(diào)用一個方法時,控制程序轉(zhuǎn)移到被調(diào)用的方法,方法將會返回兩個條件給調(diào)用者:
- 返回一條執(zhí)行語句
- 執(zhí)行到方法結(jié)束
將返回void的方法作為一個調(diào)用語句,讓我看下面的例子:
1
|
System.out.println( "wiki.jikexueyuan.com!" ); |
該方法的返回值可以通過下面的例子被理解:
1
|
int result = sum( 6 , 9 ); |
示例
下面的例子表明了怎么定義方法和怎么調(diào)用它:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class ExampleMinNumber{ public static void main(String[] args) { int a = 11 ; int b = 6 ; int c = minFunction(a, b); System.out.println( "Minimum Value = " + c); } /** returns the minimum of two numbers */ public static int minFunction( int n1, int n2) { int min; if (n1 > n2) min = n2; else min = n1; return min; } } |
將會產(chǎn)生如下的結(jié)果
1
|
Minimum value = 6 |
關(guān)鍵字 void
關(guān)鍵字 void 允許我們創(chuàng)建一個沒有返回值的方法。這里我們在下一個例子中創(chuàng)建一個 void 方法 methodRankPoints。這個方法是沒有返回值類型的。調(diào)用 void 方法必須聲明 methodRankPoints(255.7); Java 語句以分號結(jié)束,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class ExampleVoid { public static void main(String[] args) { methodRankPoints( 255.7 ); } public static void methodRankPoints( double points) { if (points >= 202.5 ) { System.out.println( "Rank:A1" ); } else if (points >= 122.4 ) { System.out.println( "Rank:A2" ); } else { System.out.println( "Rank:A3" ); } } } |
這將產(chǎn)生如下的結(jié)果:
1
|
Rank:A1 |
通過值來傳遞參數(shù)
在調(diào)用函數(shù)時參數(shù)是必須被傳遞的。并且他們的次序必須和他們創(chuàng)建時的參數(shù)次序是一樣的。參數(shù)可以通過值或引用來傳遞。
通過值傳遞參數(shù)意味著調(diào)用方法的參數(shù),通過參數(shù)值來傳遞給參數(shù)。
示例
下面的程序給出了一個例子來顯示通過值來傳遞參數(shù)。在調(diào)用方法后參數(shù)值是不會發(fā)生變化的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public class swappingExample { public static void main(String[] args) { int a = 30 ; int b = 45 ; System.out.println( "Before swapping, a = " + a + " and b = " + b); // Invoke the swap method swapFunction(a, b); System.out.println( "\n**Now, Before and After swapping values will be same here**:" ); System.out.println( "After swapping, a = " + a + " and b is " + b); } public static void swapFunction( int a, int b) { System.out.println( "Before swapping(Inside), a = " + a + " b = " + b); // Swap n1 with n2 int c = a; a = b; b = c; System.out.println( "After swapping(Inside), a = " + a + " b = " + b); } } |
這將產(chǎn)生如下的結(jié)果:
1
2
3
4
5
6
|
Before swapping, a = 30 and b = 45 Before swapping(Inside), a = 30 b = 45 After swapping(Inside), a = 45 b = 30 **Now, Before and After swapping values will be same here**: After swapping, a = 30 and b is 45 |
方法的重載
當(dāng)一個方法有兩個或者更多的方法,他們的名字一樣但是參數(shù)不同時,就叫做方法的重載。它與覆蓋是不同的。覆蓋是指方法具有相同的名字,類型以及參數(shù)的個數(shù)。
讓我們來考慮之前的找最小整型數(shù)的例子。如果我們要求尋找浮點(diǎn)型中最小的數(shù)時,我們就需要利用方法的重載來去創(chuàng)建函數(shù)名相同,但參數(shù)不一樣的兩個或更多的方法。
下面的例子給予解釋:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
public class ExampleOverloading{ public static void main(String[] args) { int a = 11 ; int b = 6 ; double c = 7.3 ; double d = 9.4 ; int result1 = minFunction(a, b); // same function name with different parameters double result2 = minFunction(c, d); System.out.println( "Minimum Value = " + result1); System.out.println( "Minimum Value = " + result2); } // for integer public static int minFunction( int n1, int n2) { int min; if (n1 > n2) min = n2; else min = n1; return min; } // for double public static double minFunction( double n1, double n2) { double min; if (n1 > n2) min = n2; else min = n1; return min; } } |
這將產(chǎn)生如下結(jié)果:
1
2
|
Minimum Value = 6 Minimum Value = 7.3 |
重載方法使程序易讀。在這里,兩種方法名稱相同但參數(shù)不同。產(chǎn)生整型和浮點(diǎn)類型的最小數(shù)作為程序運(yùn)行結(jié)果。
使用命令行參數(shù)
有時你想要在程序運(yùn)行之前傳遞參數(shù)。這可以通過給 main 函數(shù)傳遞命令行參數(shù)來實現(xiàn)。
在命令行中,當(dāng)要執(zhí)行程序文件時,一個命令行參數(shù)是緊接著文件名字后面的出現(xiàn)的。要接受命令行參數(shù)在 Java 程序中是十分容易的。它們傳遞到 main 函數(shù)字符數(shù)組內(nèi)。
示例
下面的例子展示了將所有命令行參數(shù)輸出的程序:
1
2
3
4
5
6
7
8
9
|
public class CommandLine { public static void main(String args[]){ for ( int i= 0 ; i<args.length; i++){ System.out.println( "args[" + i + "]: " + args[i]); } } } |
通過以下方法來執(zhí)行該程序:
1
|
java CommandLine this is a command line 200 -100 |
這將產(chǎn)生如下的結(jié)果:
1
2
3
4
5
6
7
|
args[0]: this args[1]: is args[2]: a args[3]: command args[4]: line args[5]: 200 args[6]: -100 |
構(gòu)造函數(shù)
這是一個簡單的使用構(gòu)造函數(shù)的例子:
1
2
3
4
5
6
7
8
9
|
// A simple constructor. class MyClass { int x; // Following is the constructor MyClass() { x = 10 ; } } |
你可以通過以下方法來調(diào)用構(gòu)造函數(shù)來實例化一個對象:
1
2
3
4
5
6
7
8
|
public class ConsDemo { public static void main(String args[]) { MyClass t1 = new MyClass(); MyClass t2 = new MyClass(); System.out.println(t1.x + " " + t2.x); } } |
通常,你將需要用構(gòu)造函數(shù)來接受一個或多個參數(shù)。參數(shù)的傳遞和以上介紹的普通方法的參數(shù)傳遞是一樣的,就是在構(gòu)造函數(shù)的名字后面列出參數(shù)列表。
示例
這是一個簡單的使用構(gòu)造函數(shù)的例子:
1
2
3
4
5
6
7
8
9
|
// A simple constructor. class MyClass { int x; // Following is the constructor MyClass( int i ) { x = i; } } |
你可以通過以下方法來調(diào)用構(gòu)造函數(shù)來實例化一個對象:
1
2
3
4
5
6
7
8
|
public class ConsDemo { public static void main(String args[]) { MyClass t1 = new MyClass( 10 ); MyClass t2 = new MyClass( 20 ); System.out.println(t1.x + " " + t2.x); } } |
這將產(chǎn)生如下的結(jié)果:
1
|
10 20 |
可變長參數(shù)
JDK1.5 能夠允許你傳遞可變長的同一類型的參數(shù)。用如下方法進(jìn)行聲明:
1
|
typeName... parameterName |
方法聲明時,你要在省略號前明確參數(shù)類型,并且只能有一個可變長參數(shù),并且可變長參數(shù)必須是所有參數(shù)的最后一個。
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class VarargsDemo { public static void main(String args[]) { // Call method with variable args printMax( 34 , 3 , 3 , 2 , 56.5 ); printMax( new double []{ 1 , 2 , 3 }); } public static void printMax( double ... numbers) { if (numbers.length == 0 ) { System.out.println( "No argument passed" ); return ; } double result = numbers[ 0 ]; for ( int i = 1 ; i < numbers.length; i++) if (numbers[i] > result) result = numbers[i]; System.out.println( "The max value is " + result); } } |
這將產(chǎn)生如下的結(jié)果:
1
2
|
The max value is 56.5 The max value is 3.0 |
finalize() 方法
你可以定義一個方法,僅在被垃圾收集器銷毀之前才會被調(diào)用。這個方法叫做 finalize() 方法,它也可以用來確保一個對象被干凈清除了。
舉個例子,你也許用 finalize() 來確保被一個對象打開的文件已經(jīng)關(guān)閉了。
為了給類添加一個終結(jié)器,你只需定義 finalize() 方法。Java要回收該類的一個對象時,會調(diào)用該方法。
在 finalize() 方法中,你將指定一些必須在對象銷毀之前要做的行為。
finalize()方法一般是如下形似:
1
2
3
4
|
protected void finalize( ) { // finalization code here } |
這里,關(guān)鍵字 protected 是為了保證在類外的代碼不能訪問 finalize() 方法。
這意味著你不能知道 finalize() 什么時候執(zhí)行。舉個例子,如果你的程序在垃圾收集器發(fā)生之前就結(jié)束了,finalize() 方法將不會被執(zhí)行。
泛型方法:
java泛型方法在方法返回值是容器類對象時廣泛使用。
1
2
3
|
public static List<T> find(Class<T> clazz,String userId){ .... } |
一般來說編寫java泛型方法時,返回值類型和至少一個參數(shù)類型應(yīng)該是泛型,而且類型應(yīng)該是一致的,如果只有返回值類型或參數(shù)類型之一使用了泛型,這個泛型方法的使用就大大的限制了,基本限制到跟不用泛型一樣的程度。
下面主要介紹兩種十分相似的java泛型方法的使用以及它們之間的區(qū)別。
第一種:
1
2
3
4
5
6
7
8
|
public static <T extends CommonService> T getService(Class<T> clazz) { T service = (T) serviceMap.get(clazz.getName()); if (service == null ) { service = (T) ServiceLocator.getService(clazz.getName()); serviceMap.put(clazz.getName(), service); } return service; } |
第二種:
1
2
3
4
5
6
7
8
|
public static <T> T getService(Class<? extends CommonService> clazz) { T service = (T) serviceMap.get(clazz.getName()); if (service == null ) { service = (T) ServiceLocator.getService(clazz.getName()); serviceMap.put(clazz.getName(), service); } return service; } |
下面是泛型方法所在的類:
1
2
3
4
5
6
7
|
public abstract class CommonService { private static HashMap<String, CommonService> serviceMap = new HashMap<String, CommonService>(); //這里是泛型方法定義 . . . } |
這兩個泛型方法只有方法的簽名不一樣,方法體完全相同,那它們有什么不一樣呢?
我們來使用一下它們,就知道它們的區(qū)別了。
對第一種泛型方法使用:
1
2
3
4
5
6
7
|
public class Main { public static void main(String[] args) { NoticeService noticeService=CommonService.getService(NoticeService. class ); //正確的使用第一種泛型方法,不會出現(xiàn)編譯錯誤。 NoticeService noticeService=CommonService.getService(UserService. class ); //不正確的使用第一種泛型方法,會出現(xiàn)編譯錯誤。 } } |
對第二種泛型方法使用:
1
2
3
4
5
6
7
|
public class Main { public static void main(String[] args) { NoticeService noticeService=CommonService.getService(NoticeService. class ); //正確的使用第二種泛型方法,不會出現(xiàn)編譯錯誤,邏輯也正確,運(yùn)行時不會出現(xiàn)異常。 NoticeService noticeService=CommonService.getService(UserService. class ); //不正確的使用第二種泛型方法,不會出現(xiàn)編譯錯誤,但邏輯不正確,運(yùn)行時會出現(xiàn)異常,危險! } } |
現(xiàn)在知道了這兩種極其相似的泛型方法的區(qū)別了吧?
- 第一種泛型方法:返回值和參數(shù)值的類型是一致,推薦使用;
- 第二種泛型方法:返回值和參數(shù)值的類型不是一致,請謹(jǐn)慎或避免使用。