Java 可變參數列表
class A {}
由于所有的類都繼承于Object,可以以Object數組為參數的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class parameter { static void printArray(Object[] args){ for (Object obj : args){ System.out.print(obj + " " ); } System.out.println(); } public static void main(String[] args){ printArray( new Object[] { new Integer( 47 ), new Float( 3.14 ), new Double( 11.11 ) }); printArray( new Object[]{ "one" , "two" , "there" }); printArray( new Object[]{ new A(), new A(), new A()}); } } |
對于Java SE5之后版本添加了特性可以如此寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class parameter { public static void printArray(Object... args){ for (Object obj : args){ System.out.print(obj + " " ); } System.out.println(); } public static void main(String[] args){ printArray( new Integer( 47 ), new Float( 3.14 ), new Double( 11.11 )); printArray( 47 , 3 .14F, 11.11 ); printArray( "one" , "two" , "three" ); printArray( new A(), new A(), new A()); printArray((Object[]) new Integer[]{ 1 , 2 , 3 , 4 }); printArray(); } } |
可以使用Object以為的參數列表:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class VarargType{ static void f(Character... args){ System.out.print(args.getClass()); System.out.println( " length " + args.length); } static void g( int ... args){ System.out.print(args.getClass()); System.out.println( " length " + args.length); } public static void main(String[] args){ f( 'a' ); f(); g( 1 ); g(); System.out.println( " int [] " + new int [ 0 ].getClass()); } } |
這是 Java 5 引入的一個特性,如果一個方法要接收的參數數量是不確定的,那么這個特性就可以派上用場了。
比如,在涉及IO操作的地方,基本上至少需要關閉兩個流:輸入、輸出,我喜歡把流關閉的操作封裝成下面的方法,這樣只需一次調用就可以關閉多個流。
1
2
3
4
5
6
7
8
9
10
|
public static void closeSilent(Closeable... closeables) { for (Closeable closeable : closeables) { if (closeable != null ) { try { closeable.close(); } catch (IOException ignored) { } } } } |
這是我覺得這個特性唯一適合使用的地方,具備下面的特點:
這些參數具有相同的類型;
參數數量不確定,每一個都是可選的;
這些參數的用途都是一樣的,比如上面都是執行關閉。
Java 可變長參數列表只能放在方法參數列表的最后。
Java可變長參數列表的實現
Java可變長參數列表的實現是通過編譯器把把這些參數封裝成一個數組來傳遞的。
比如上面的方法的簽名實際上是: closeSilent(Closeable[] closeables) void 。
踩坑
有個方法,被 A、B 兩個地方 A、B 調用,9 月,在 A 這里需要增加一個參數,當時腦子一抽瘋,決定用可變長參數列表,覺得 B 那里不用改簡單點,坑就這樣埋下了。
最近要求 B 這里要新增兩個參數,那就在方法的參數列表里繼續加參數,這些參數的類型是不同的,所以可變長參數列表聲明成 Object 類型的。
第一個坑就是在這個方法內取可變長參數的元素時,沒考慮到有的參數是沒傳的,直接爆數組越位的異常了。馬上就覺得可變長參數列表的不好了,那就不用了唄,改為常規的固定形式的參數傳遞。
改完之后,在測試環境測了都沒問題。把生產環境的幾個類替換之后,結果卻報錯了,方法找不到,一看方法簽名,還是數組的,沒有替換到。從源碼看,那個調用的地方不需要更改,所以沒想到要替換;由于測試環境是全量打包,所以不會出現問題。
方法的簽名是在編譯的時候就確定了的,源碼層面看起來不需要改的不表示編譯后的類也不需要替換了。
其實以前也聽到過,在這種發包不規范的情況下,把源碼里的一個常量值改了之后,只替換了這個定義常量的類文件,沒有把所有引用這個常量的類文件重新編譯替換,導致出現莫名其妙的問題。跟方法簽名的情況本質上是一樣的問題。