Java中的可變參數(shù)(Varargs)

1. 簡(jiǎn)介
可變參數(shù)(Varargs)在Java 5中被引入,它為支持一種類型的任意數(shù)量參數(shù)的方法提供了一種簡(jiǎn)便寫(xiě)法。在本文中,我們將了解如何使用這個(gè)Java核心特性。

2. 在可變參數(shù)(Varargs)之前
在Java 5之前,每當(dāng)我們想要傳遞任意數(shù)量的參數(shù)時(shí),我們必須將所有參數(shù)放在一個(gè)數(shù)組中傳遞,或者實(shí)現(xiàn)N個(gè)方法(每增加一個(gè)參數(shù)就實(shí)現(xiàn)一個(gè)方法):

public String format() {... }
    public String format(String value) {... }
    public String format(String val1, String val2) {... }

3. 可變參數(shù)(Varargs)的使用
可變參數(shù)(Varargs)通過(guò)引入能夠自動(dòng)處理任意數(shù)量參數(shù)的新語(yǔ)法(在底層使用數(shù)組),幫助我們避免編寫(xiě)樣板代碼。我們可以使用標(biāo)準(zhǔn)類型聲明,后跟省略號(hào)(...)來(lái)定義它們:

public String formatWithVarArgs(String... values) {
        //...
    }

現(xiàn)在,我們可以使用任意數(shù)量的參數(shù)來(lái)調(diào)用我們的方法,例如:

formatWithVarArgs();
    formatWithVarArgs("a", "b", "c", "d");

如前所述,可變參數(shù)(Varargs)就是數(shù)組,所以我們需要像處理普通數(shù)組一樣處理它們。

4. 規(guī)則
可變參數(shù)(Varargs)使用起來(lái)很簡(jiǎn)單,但我們需要記住一些規(guī)則:

  • 每個(gè)方法只能有一個(gè)可變參數(shù)(Varargs)參數(shù)
  • 可變參數(shù)(Varargs)參數(shù)必須是最后一個(gè)參數(shù)

5. 堆污染
使用可變參數(shù)(Varargs)可能會(huì)導(dǎo)致所謂的堆污染。為了更好地理解堆污染,請(qǐng)考慮這個(gè)可變參數(shù)(Varargs)方法:

static String firstOfFirst(List<String>... strings) {
        List<Integer> ints = Collections.singletonList(42);
        Object[] objects = strings;
        objects[0] = ints; // 堆污染
        return strings[0].get(0); // 類轉(zhuǎn)換異常
    }

如果我們?cè)跍y(cè)試中調(diào)用這個(gè)奇怪的方法:

String one = firstOfFirst(Arrays.asList("one", "two"), Collections.emptyList());
    assertEquals("one", one);

我們將會(huì)得到一個(gè)類轉(zhuǎn)換異常:

java.lang.ClassCastException: class java.lang.Integer不能轉(zhuǎn)換為class java.lang.String

5.1. 安全使用
每次我們使用可變參數(shù)(Varargs)時(shí),Java編譯器都會(huì)創(chuàng)建一個(gè)數(shù)組來(lái)保存給定的參數(shù)。在這種情況下,編譯器會(huì)創(chuàng)建一個(gè)具有泛型類型組件的數(shù)組來(lái)保存參數(shù)。當(dāng)我們將可變參數(shù)與泛型類型一起使用時(shí),由于存在潛在的運(yùn)行時(shí)異常,Java編譯器會(huì)警告可能存在不安全的可變參數(shù)使用:

警告: [varargs] 來(lái)自參數(shù)化可變參數(shù)類型T的可能的堆污染

5.2. 可變參數(shù)引用的逃逸
讓我們考慮可變參數(shù)的另一種不安全用法:

static <T> T[] toArray(T... arguments) {
        return arguments;
    }

6. 結(jié)論
在Java中,可變參數(shù)(Varargs)可以消除大量樣板代碼,簡(jiǎn)化代碼結(jié)構(gòu)。

若你想提升Java技能,可關(guān)注我們的Java培訓(xùn)課程。