6.java可變參數(shù)(轉(zhuǎn))

Java1.5增加了新特性:可變參數(shù):適用于參數(shù)個數(shù)不確定,類型確定的情況,java把可變參數(shù)當(dāng)做數(shù)組處理吧秕。注意:可變參數(shù)必須位于最后一項惨寿。當(dāng)可變參數(shù)個數(shù)多余一個時邦泄,必將有一個不是最后一項,所以只支持有一個可變參數(shù)裂垦。因為參數(shù)個數(shù)不定顺囊,所以當(dāng)其后邊還有相同類型參數(shù)時,java無法區(qū)分傳入的參數(shù)屬于前一個可變參數(shù)還是后邊的參數(shù)蕉拢,所以只能讓可變參數(shù)位于最后一項特碳。

可變參數(shù)的特點:

(1)、只能出現(xiàn)在參數(shù)列表的最后晕换;

(2)午乓、...位于變量類型和變量名之間,前后有無空格都可以闸准;

(3)益愈、調(diào)用可變參數(shù)的方法時,編譯器為該可變參數(shù)隱含創(chuàng)建一個數(shù)組,在方法體中一數(shù)組的形式訪問可變參數(shù)蒸其。

https://www.cnblogs.com/uptownBoy/articles/1698335.html

到J2SE 1.4為止敏释,一直無法在Java程序里定義實參個數(shù)可變的方法——因為Java要求實參(Arguments)和形參(Parameters)的數(shù)量和類型都必須逐一匹配,而形參的數(shù)目是在定義方法時就已經(jīng)固定下來了摸袁。盡管可以通過重載機制钥顽,為同一個方法提供帶有不同數(shù)量的形參的版本,但是這仍然不能達到讓實參數(shù)量任意變化的目的靠汁。
然而蜂大,有些方法的語義要求它們必須能接受個數(shù)可變的實參——例如著名的main方法,就需要能接受所有的命令行參數(shù)為實參蝶怔,而命令行參數(shù)的數(shù)目奶浦,事先根本無法確定下來。
對于這個問題添谊,傳統(tǒng)上一般是采用“利用一個數(shù)組來包裹要傳遞的實參”的做法來應(yīng)付财喳。

1. 用數(shù)組包裹實參

“用數(shù)組包裹實參”的做法可以分成三步:首先,為這個方法定義一個數(shù)組型的參數(shù)斩狱;然后在調(diào)用時耳高,生成一個包含了所有要傳遞的實參的數(shù)組;最后所踊,把這個數(shù)組作為一個實參傳遞過去泌枪。
這種做法可以有效的達到“讓方法可以接受個數(shù)可變的參數(shù)”的目的,只是調(diào)用時的形式不夠簡單秕岛。
J2SE 1.5中提供了Varargs機制碌燕,允許直接定義能和多個實參相匹配的形參。從而继薛,可以用一種更簡單的方式修壕,來傳遞個數(shù)可變的實參。
Varargs的含義
大體說來遏考,“Varargs”是“variable number of arguments”的意思慈鸠。有時候也被簡單的稱為“variable arguments”,不過因為這一種叫法沒有說明是什么東西可變灌具,所以意義稍微有點模糊青团。

2. 定義實參個數(shù)可變的方法

只要在一個形參的“類型”與“參數(shù)名”之間加上三個連續(xù)的“.”(即“...”,英文里的句中省略號)咖楣,就可以讓它和不確定個實參相匹配督笆。而一個帶有這樣的形參的方法,就是一個實參個數(shù)可變的方法诱贿。

清單1:一個實參個數(shù)可變的方法
private static int sumUp(int... values) {
}

注意娃肿,只有最后一個形參才能被定義成“能和不確定個實參相匹配”的。因此,一個方法里只能有一個這樣的形參咸作。另外锨阿,如果這個方法還有其它的形參,要把它們放到前面的位置上记罚。

編譯器會在背地里把這最后一個形參轉(zhuǎn)化為一個數(shù)組形參,并在編譯出的class文件里作上一個記號壳嚎,表明這是個實參個數(shù)可變的方法桐智。

清單2:實參個數(shù)可變的方法的秘密形態(tài)
private static int sumUp(int[] values) {
}

由于存在著這樣的轉(zhuǎn)化,所以不能再為這個類定義一個和轉(zhuǎn)化后的方法簽名一致的方法烟馅。

清單3:會導(dǎo)致編譯錯誤的組合
private static int sumUp(int... values) {
}
private static int sumUp(int[] values) {
}

3. 調(diào)用實參個數(shù)可變的方法

只要把要傳遞的實參逐一寫到相應(yīng)的位置上说庭,就可以調(diào)用一個實參個數(shù)可變的方法。不需要其它的步驟郑趁。

清單4:可以傳遞若干個實參
sumUp(1, 3, 5, 7);

在背地里刊驴,編譯器會把這種調(diào)用過程轉(zhuǎn)化為用“數(shù)組包裹實參”的形式:

清單5:偷偷出現(xiàn)的數(shù)組創(chuàng)建
sumUp(new int[]{1, 2, 3, 4});

另外,這里說的“不確定個”也包括零個寡润,所以這樣的調(diào)用也是合乎情理的:

清單6:也可以傳遞零個實參
sumUp();

這種調(diào)用方法被編譯器秘密轉(zhuǎn)化之后的效果捆憎,則等同于這樣:

清單7:零實參對應(yīng)空數(shù)組
sumUp(new int[]{});

注意這時傳遞過去的是一個空數(shù)組,而不是null梭纹。這樣就可以采取統(tǒng)一的形式來處理躲惰,而不必檢測到底屬于哪種情況。

4. 處理個數(shù)可變的實參

處理個數(shù)可變的實參的辦法变抽,和處理數(shù)組實參的辦法基本相同础拨。所有的實參,都被保存到一個和形參同名的數(shù)組里绍载。根據(jù)實際的需要诡宗,把這個數(shù)組里的元素讀出之后,要蒸要煮击儡,就可以隨意了塔沃。

清單8:處理收到的實參們
private static int sumUp(int... values) {
 int sum = 0;
 for (int i = 0; i < values.length; i++) {
  sum += values[i];
 }
 return sum;
}

5. 轉(zhuǎn)發(fā)個數(shù)可變的實參

有時候,在接受了一組個數(shù)可變的實參之后曙痘,還要把它們傳遞給另一個實參個數(shù)可變的方法芳悲。因為編碼時無法知道接受來的這一組實參的數(shù)目,所以“把它們逐一寫到該出現(xiàn)的位置上去”的做法并不可行边坤。不過名扛,這并不意味著這是個不可完成的任務(wù),因為還有另外一種辦法茧痒,可以用來調(diào)用實參個數(shù)可變的方法肮韧。

在J2SE 1.5的編譯器的眼中,實參個數(shù)可變的方法是最后帶了一個數(shù)組形參的方法的特例。因此弄企,事先把整組要傳遞的實參放到一個數(shù)組里超燃,然后把這個數(shù)組作為最后一個實參,傳遞給一個實參個數(shù)可變的方法拘领,不會造成任何錯誤意乓。借助這一特性,就可以順利的完成轉(zhuǎn)發(fā)了约素。

清單9:轉(zhuǎn)發(fā)收到的實參們
public class PrintfSample {
  public static void main(String[] args) {
    printOut("Pi:%f E:%f\n", Math.PI, Math.E);
  }
  private static void printOut(String format, Object... args) {
    System.out.printf(format, args);
 }
}

6. 是數(shù)組届良?不是數(shù)組?

盡管在背地里圣猎,編譯器會把能匹配不確定個實參的形參士葫,轉(zhuǎn)化為數(shù)組形參;而且也可以用數(shù)組包了實參送悔,再傳遞給實參個數(shù)可變的方法慢显;但是,這并不表示“能匹配不確定個實參的形參”和“數(shù)組形參”完全沒有差異欠啤。

一個明顯的差異是荚藻,如果按照調(diào)用實參個數(shù)可變的方法的形式,來調(diào)用一個最后一個形參是數(shù)組形參的方法跪妥,只會導(dǎo)致一個“cannot be applied to”的編譯錯誤鞋喇。

清單10:一個“cannot be applied to”的編譯錯誤
private static void testOverloading(int[] i) {
System.out.println("A");
}
public static void main(String[] args) {
testOverloading(1, 2, 3);//編譯出錯
}

由于這一原因,不能在調(diào)用只支持用數(shù)組包裹實參的方法的時候(例如在不是專門為J2SE 1.5設(shè)計第三方類庫中遺留的那些)眉撵,直接采用這種簡明的調(diào)用方式侦香。

如果不能修改原來的類,為要調(diào)用的方法增加參數(shù)個數(shù)可變的版本纽疟,而又想采用這種簡明的調(diào)用方式罐韩,那么可以借助“引入外加函數(shù)(Introduce Foreign Method)”和“引入本地擴展(Intoduce Local Extension)”的重構(gòu)手法來近似的達到目的。

7. 當(dāng)個數(shù)可變的實參遇到泛型

J2SE 1.5中新增了“泛型”的機制污朽,可以在一定條件下把一個類型參數(shù)化散吵。例如,可以在編寫一個類的時候蟆肆,把一個方法的形參的類型用一個標(biāo)識符(如T)來代表矾睦,至于這個標(biāo)識符到底表示什么類型,則在生成這個類的實例的時候再行指定炎功。這一機制可以用來提供更充分的代碼重用和更嚴(yán)格的編譯時類型檢查枚冗。

不過泛型機制卻不能和個數(shù)可變的形參配合使用。如果把一個能和不確定個實參相匹配的形參的類型蛇损,用一個標(biāo)識符來代表赁温,那么編譯器會給出一個“generic array creation”的錯誤坛怪。

清單11:當(dāng)Varargs遇上泛型
private static void testVarargs(T... args) {//編譯出錯
}

造成這個現(xiàn)象的原因在于J2SE 1.5中的泛型機制的一個內(nèi)在約束——不能拿用標(biāo)識符來代表的類型來創(chuàng)建這一類型的實例。在出現(xiàn)支持沒有了這個約束的Java版本之前股囊,對于這個問題袜匿,基本沒有太好的解決辦法。

不過稚疹,傳統(tǒng)的“用數(shù)組包裹”的做法居灯,并不受這個約束的限制。

清單12:可以編譯的變通做法
private static void testVarargs(T[] args) {
 for (int i = 0; i < args.length; i++) {
  System.out.println(args[i]);
 }
}

8. 重載中的選擇問題

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ù)可變的版本”敞贡。

清單13:實參個數(shù)固定的版本優(yōu)先

如果在編譯器看來泵琳,同時有多個方法具有相同的優(yōu)先權(quán),它就會陷入無法就到底調(diào)用哪個方法作出一個選擇的狀態(tài)誊役。在這樣的時候获列,它就會產(chǎn)生一個“reference to 被調(diào)用的方法名 is ambiguous”的編譯錯誤,并耐心的等候作了一些修改蛔垢,足以免除它的迷惑的新源代碼的到來击孩。

在引入了Varargs機制之后,這種可能導(dǎo)致迷惑的情況啦桌,又增加了一些溯壶。例如現(xiàn)在可能會有兩個版本都能匹配及皂,在其它方面也如出一轍,而且都是實參個數(shù)可變的沖突發(fā)生且改。

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機制之后,這種可能導(dǎo)致迷惑的情況礼烈,又增加了一些弧满。例如現(xiàn)在可能會有兩個版本都能匹配,在其它方面也如出一轍此熬,而且都是實參個數(shù)可變的沖突發(fā)生庭呜。

清單14:左右都不是,為難了編譯器
public class OverloadingSampleB {
 public static void main(String[] args) {
  testOverloading(1, 2, 3);//編譯出錯
 }
 private static void testOverloading(Object... args) {
 }
 private static void testOverloading(Object o, Object... args) {
 }
}

另外犀忱,因為J2SE 1.5中有“Autoboxing/Auto-Unboxing”(自動裝/拆箱)機制的存在募谎,所以還可能發(fā)生兩個版本都能匹配,而且都是實參個數(shù)可變阴汇,其它方面也一模一樣数冬,只是一個能接受的實參是基本類型,而另一個能接受的實參是包裹類的沖突發(fā)生搀庶。

清單15:Autoboxing/Auto-Unboxing帶來的新問題
public class OverloadingSampleC {
 public static void main(String[] args) {
  /* 編譯出錯 */
  testOverloading(1, 2);
  /* 還是編譯出錯 */
  testOverloading(new Integer(1), new Integer(2));
 }
 private static void testOverloading(int... args) {
 }
 private static void testOverloading(Integer... args) {
 }
}

9. 歸納總結(jié)

和“用數(shù)組包裹”的做法相比拐纱,真正的實參個數(shù)可變的方法,在調(diào)用時傳遞參數(shù)的操作更為簡單地来,含義也更為清楚戳玫。不過,這一機制也有它自身的局限未斑,并不是一個完美無缺的解決方案咕宿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蜡秽,隨后出現(xiàn)的幾起案子府阀,更是在濱河造成了極大的恐慌,老刑警劉巖芽突,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件试浙,死亡現(xiàn)場離奇詭異,居然都是意外死亡寞蚌,警方通過查閱死者的電腦和手機田巴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門钠糊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人壹哺,你說我怎么就攤上這事抄伍。” “怎么了管宵?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵截珍,是天一觀的道長。 經(jīng)常有香客問我箩朴,道長岗喉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任炸庞,我火速辦了婚禮钱床,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埠居。我一直安慰自己诞丽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布拐格。 她就那樣靜靜地躺著,像睡著了一般刑赶。 火紅的嫁衣襯著肌膚如雪捏浊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天撞叨,我揣著相機與錄音金踪,去河邊找鬼。 笑死牵敷,一個胖子當(dāng)著我的面吹牛胡岔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播枷餐,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼靶瘸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毛肋?” 一聲冷哼從身側(cè)響起怨咪,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎润匙,沒想到半個月后诗眨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡孕讳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年匠楚,在試婚紗的時候發(fā)現(xiàn)自己被綠了巍膘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡芋簿,死狀恐怖峡懈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情益咬,我是刑警寧澤逮诲,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站幽告,受9級特大地震影響梅鹦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜冗锁,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一齐唆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冻河,春花似錦箍邮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至擂错,卻和暖如春味滞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钮呀。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工剑鞍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爽醋。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓蚁署,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蚂四。 傳聞我的和親對象是個殘疾皇子光戈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容