在Java5 中提供了變長參數(varargs),也就是在方法定義中可使用個數不肯定的參數,對於同一方法可使用不一樣個數的參數調用,例如print("hello");print("hello","lisi");print("hello","張三", "alexia");下面介紹如何定義可變長參數 以及如何使用可變長參數。
1. 可變長參數的定義java
使用...表示可變長參數,例如
print(String... args){
...
}
在具備可變長參數的方法中能夠把參數當成數組使用,例如能夠循環輸出全部的參數值。
print(String... args){
for(String temp:args)
System.out.println(temp);
}
2. 可變長參數的方法的調用
調用的時候能夠給出任意多個參數也可不給參數,例如:數組
print();
print("hello");
print("hello","lisi");
print("hello","張三", "alexia")
3. 可變長參數的使用規則
3.1 在調用方法的時候,若是可以和固定參數的方法匹配,也可以與可變長參數的方法匹配,則選擇固定參數的方法。看下面代碼的輸出:ide
package com; // 這裏使用了靜態導入 import static java.lang.System.out; public class VarArgsTest { public void print(String... args) { for (int i = 0; i < args.length; i++) { out.println(args[i]); } } public void print(String test) { out.println("----------"); } public static void main(String[] args) { VarArgsTest test = new VarArgsTest(); test.print("hello"); test.print("hello", "alexia"); } }
3.2 若是要調用的方法能夠和兩個可變參數匹配,則出現錯誤,例以下面的代碼:編碼
package com; // 這裏使用了靜態導入 import static java.lang.System.out; public class VarArgsTest1 { public void print(String... args) { for (int i = 0; i < args.length; i++) { out.println(args[i]); } } public void print(String test,String...args ){ out.println("----------"); } public static void main(String[] args) { VarArgsTest1 test = new VarArgsTest1(); test.print("hello"); test.print("hello", "alexia"); } }
對於上面的代碼,main方法中的兩個調用都不能編譯經過,由於編譯器不知道該選哪一個方法調用,以下所示:spa
3.3 一個方法只能有一個可變長參數,而且這個可變長參數必須是該方法的最後一個參數
如下兩種方法定義都是錯誤的。
public void test(String... strings,ArrayList list){
}
public void test(String... strings,ArrayList... list){
}
code
4. 可變長參數的使用規範對象
4.1 避免帶有可變長參數的方法重載:如3.1中,編譯器雖然知道怎麼調用,但人容易陷入調用的陷阱及誤區blog
4.2 別讓null值和空值威脅到變長方法,如3.2中所示,爲了說明null值的調用,從新給出一個例子:編譯器
package com;public class VarArgsTest1 { public void print(String test, Integer... is) { } public void print(String test,String...args ){ } public static void main(String[] args) { VarArgsTest1 test = new VarArgsTest1(); test.print("hello"); test.print("hello", null); } }
這時會發現兩個調用編譯都不經過:string
由於兩個方法都匹配,編譯器不知道選哪一個,因而報錯了,這裏同時還有個很是很差的編碼習慣,即調用者隱藏了實參類型,這是很是危險的,不只僅調用者須要「猜想」該調用哪一個方法,並且被調用者也可能產生內部邏輯混亂的狀況。對於本例來講應該作以下修改:
public static void main(String[] args) { VarArgsTest1 test = new VarArgsTest1(); String[] strs = null; test.print("hello", strs); }
4.3 覆寫變長方法也要循規蹈矩
下面看一個例子,你們猜想下程序能不能編譯經過:
package com; public class VarArgsTest2 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub // 向上轉型 Base base = new Sub(); base.print("hello"); // 不轉型 Sub sub = new Sub(); sub.print("hello"); } } // 基類 class Base { void print(String... args) { System.out.println("Base......test"); } } // 子類,覆寫父類方法 class Sub extends Base { @Override void print(String[] args) { System.out.println("Sub......test"); } }
答案固然是編譯不經過,是否是以爲很奇怪?
第一個能編譯經過,這是爲何呢?事實上,base對象把子類對象sub作了向上轉型,形參列表是由父類決定的,固然能經過。而看看子類直接調用的狀況,這時編譯器看到子類覆寫了父類的print方法,所以確定使用子類從新定義的print方法,儘管參數列表不匹配也不會跑到父類再去匹配下,由於找到了就再也不找了,所以有了類型不匹配的錯誤。
這是個特例,覆寫的方法參數列表居然能夠與父類不相同,這違背了覆寫的定義,而且會引起莫名其妙的錯誤。
這裏,總結下覆寫必須知足的條件:
(1)重寫方法不能縮小訪問權限;
(2)參數列表必須與被重寫方法相同(包括顯示形式);
(3)返回類型必須與被重寫方法的相同或是其子類;
(4)重寫方法不能拋出新的異常,或者超過了父類範圍的異常,可是能夠拋出更少、更有限的異常,或者不拋出異常。
最後,給出一個有陷阱的例子,你們應該知道輸出結果:
package com; public class VarArgsTest { public static void m1(String s, String... ss) { for (int i = 0; i < ss.length; i++) { System.out.println(ss[i]); } } public static void main(String[] args) { m1(""); m1("aaa"); m1("aaa", "bbb"); } }