Java 中 Varargs 机制详解
?
新的J2SE 1.5版本提供了“Varargs”這一機制。使用該機制可以定義能和多個實參相匹配的形參。從而可以用一種更簡單的方式,來傳遞個數(shù)可變的實參。本文介紹這一機制的使用方法,以及這一機制與數(shù)組、泛型、重載之間的相互作用時的若干問題。
?
? ? ? ? ? ? ? ? ? ? ?(西安芯學苑http://www.029xhl.com/)
在原來J2SE 1.4版本之前,Java程序一直無法定義實參個數(shù)可變的方法——因為Java要求實參(Arguments)和形參(Parameters)的數(shù)量和類 型都必須逐一匹配,而形參的數(shù)目是在定義方法時就已經(jīng)固定下來了。盡管可以通過重載機制,為同一個方法提供帶有不同數(shù)量的形參的版本,但是這仍然不能達到讓實參數(shù)量任意變化的目的。
?
然而,有些方法的語義要求它們必須能接受個數(shù)可變的實參——例如著名的main方法,就需要能接受所有的命令行參數(shù)為實參,而命令行參數(shù)的數(shù)目,事先根本無法確定下來。
對于這個問題,傳統(tǒng)上一般是采用“利用一個數(shù)組來包裹要傳遞的實參”的做法來應付。
?
用數(shù)組包裹實參
?
“用數(shù)組包裹實參”的做法可以分成三步:
?
一、為這個方法定義一個數(shù)組型的參數(shù);
二、在調(diào)用時,生成一個包含了所有要傳遞的實參的數(shù)組;
三、把這個數(shù)組作為一個實參傳遞過去。
?
這種做法調(diào)用時的形式不夠簡單。J2SE 1.5中提供了Varargs機制,允許直接定義能和多個實參相匹配的形參。從而,可以用一種更簡單的方式,來傳遞個數(shù)可變的實參。
?
Varargs的含義
大體說來,“Varargs”是“variable number of arguments”的意思。有時候也被簡單的稱為“variable arguments”,不過因為這一種叫法沒有說明是什么東西可變,所以意義稍微有點模糊。
?
定義實參個數(shù)可變的方法
?
只要在一個形參的“類型”與“參數(shù)名”之間加上三個連續(xù)的“.”(即“…”,英文里的句中省略號),就可以讓它和不確定個實參相匹配。而一個帶有這樣的形參的方法,就是一個實參個數(shù)可變的方法。
?
例:一個實參個數(shù)可變的方法
private static int sumUp(int... values) {
}
?
注意,只有最后一個形參才能被定義成“能和不確定個實參相匹配”的。因此,一個方法里只能有一個這樣的形參。另外,如果這個方法還有其它的形參,要把它們放到前面的位置上。
編譯器會在背地里把這最后一個形參轉(zhuǎn)化為一個數(shù)組形參,并在編譯出的class文件里作上一個記號,表明這是個實參個數(shù)可變的方法。
?
例:實參個數(shù)可變的方法的秘密形態(tài)
private static int sumUp(int[] values) {
}
?
由于存在著這樣的轉(zhuǎn)化,所以不能再為這個類定義一個和轉(zhuǎn)化后的方法簽名一致的方法。
?
例:會導致編譯錯誤的組合
private static int sumUp(int... values) {
}
private static int sumUp(int[] values) {
}
?
空白的問題
根據(jù)J2SE 1.5的語法,在“…”前面的空白字符是可有可無的。這樣就有在“…”前面添加空白字符(形如“Object … args”)和在“…”前面不加空白字符(形如“Object… args”)的兩種寫法。因為目前和J2SE 1.5相配合的Java Code Conventions還沒有正式發(fā)布,所以無法知道究竟哪一種寫法比較正統(tǒng)。不過,考慮到數(shù)組參數(shù)也有“Object [] args”和“Object[] args”兩種書寫方式,而正統(tǒng)的寫法是不在“[]”前添加空白字符,似乎采取不加空白的“Object… args”的寫法在整體上更協(xié)調(diào)一些。
?
調(diào)用實參個數(shù)可變的方法
?
只要把要傳遞的實參逐一寫到相應的位置上,就可以調(diào)用一個實參個數(shù)可變的方法。不需要其它的步驟。
?
例:可以傳遞若干個實參
sumUp(1, 3, 5, 7);
這種調(diào)用方法被編譯器秘密轉(zhuǎn)化之后的效果,則等同于這樣:
例:零實參對應空數(shù)組
sumUp(new int[]{});
注意這時傳遞過去的是一個空數(shù)組,而不是null。這樣就可以采取統(tǒng)一的形式來處理,而不必檢測到底屬于哪種情況。
?
處理個數(shù)可變的實參
?
處理個數(shù)可變的實參的辦法,和處理數(shù)組實參的辦法基本相同。所有的實參,都被保存到一個和形參同名的數(shù)組里。根據(jù)實際的需要,把這個數(shù)組里的元素讀出之后,就可以隨意了。
?
例:處理收到的實參們
private static int sumUp(int... values) {
int sum = 0;
for (int i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
}
?
轉(zhuǎn)發(fā)個數(shù)可變的實參
?
有時候,在接受了一組個數(shù)可變的實參之后,還要把它們傳遞給另一個實參個數(shù)可變的方法。因為編碼時無法知道接受來的這一組實參的數(shù)目,所以“把它們逐一寫到該出現(xiàn)的位置上去”的做法并不可行。不過,這并不意味著這是個不可完成的任務(wù),因為還有另外一種辦法,可以用來調(diào)用實參個數(shù)可變的方法。
?
在J2SE 1.5的編譯器的眼中,實參個數(shù)可變的方法是最后帶了一個數(shù)組形參的方法的特例。因此,事先把整組要傳遞的實參放到一個數(shù)組里,然后把這個數(shù)組作為最后一個實參,傳遞給一個實參個數(shù)可變的方法,不會造成任何錯誤。借助這一特性,就可以順利的完成轉(zhuǎn)發(fā)了。
?
當個數(shù)可變的實參遇到泛型
J2SE 1.5中新增了“泛型”的機制,可以在一定條件下把一個類型參數(shù)化。例如,可以在編寫一個類的時候,把一個方法的形參的類型用一個標識符(如T)來代表, 至于這個標識符到底表示什么類型,則在生成這個類的實例的時候再行指定。這一機制可以用來提供更充分的代碼重用和更嚴格的編譯時類型檢查。
?
不過泛型機制卻不能和個數(shù)可變的形參配合使用。如果把一個能和不確定個實參相匹配的形參的類型,用一個標識符來代表,那么編譯器會給出一個“generic array creation”的錯誤。
?
重載中的選擇問題
?
Java支持“重載”的機制,允許在同一個類擁有許多只有形參列表不同的方法。然后,由編譯器根據(jù)調(diào)用時的實參來選擇到底要執(zhí)行哪一個方法。
?
傳統(tǒng)上的選擇,基本是依照“特殊者優(yōu)先”的原則來進行。一個方法的特殊程度,取決于為了讓它順利運行而需要滿足的條件的數(shù)目,需要條件越多的越特殊。
?
在引入Varargs機制之后,這一原則仍然適用,只是要考慮的問題豐富了一些——傳統(tǒng)上,一個重載方法的各個版本之中,只有形參數(shù)量與實參數(shù)量正 好一致的那些有被進一步考慮的資格。但是Varargs機制引入之后,完全可以出現(xiàn)兩個版本都能匹配,在其它方面也別無二致,只是一個實參個數(shù)固定,而一 個實參個數(shù)可變的情況。
?
遇到這種情況時,所用的判定規(guī)則是“實參個數(shù)固定的版本優(yōu)先于實參個數(shù)可變的版本”。
?
例:實參個數(shù)固定的版本優(yōu)先
public class OverloadingSampleA {
public static void main(String[] args) {
testOverloading(1);// 打印出A
testOverloading(1, 2);// 打印出B
testOverloading(1, 2, 3);// 打印出C
}
private static void testOverloading(int i) {
System.out.println("A");
}
private static void testOverloading(int i, int j) {
System.out.println("B");
}
private static void testOverloading(int i, int... more) {
System.out.println("C");
}
}
?
如果在編譯器看來,同時有多個方法具有相同的優(yōu)先權(quán),它就會陷入無法就到底調(diào)用哪個方法作出一個選擇的狀態(tài)。在這樣的時候,它就會產(chǎn)生一個 “reference to 被調(diào)用的方法名 is ambiguous”的編譯錯誤,并耐心的等候作了一些修改,足以免除它的迷惑的新源代碼的到來。
在引入了Varargs機制之后,這種可能導致迷惑的情況,又增加了一些。例如現(xiàn)在可能會有兩個版本都能匹配,在其它方面也如出一轍,而且都是實參個數(shù)可變的沖突發(fā)生。
轉(zhuǎn)載于:https://www.cnblogs.com/a31415926/p/6526299.html
總結(jié)
以上是生活随笔為你收集整理的Java 中 Varargs 机制详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第一百七十二节,jQuery,动画效果
- 下一篇: 【JavaNIO的深入研究4】内存映射文