五分鐘學Java:可變參數到底是怎麼一回事?

在逛 programcreek 的時候,我發現了一些專一基礎但不容忽視的主題。好比說:Java 的可變參數到底是怎麼一回事?像這類靈魂拷問的主題,很是值得深刻地研究一下。html

之前很不重視基礎,以爲不就那麼回事嘛,會用就好了。就好比說今天這個主題,管它可變不可變呢,不就是個參數嘛,還能有多大學問——抱着這種態度,我一直橫行江湖近十載(苦笑)。可等到讀者找我提一些基礎的問題時,我幾乎回答不上來,感受知識是散的,或者是浮於表面的。幸虧最近一段時間,我開始幡然醒悟,開始不放過任何一個細節,漸漸地,有點「知識儲備」了。java

好了,牛逼吹完,讓咱們來步入正題。Java 的可變參數到底是怎麼一回事?程序員

可變參數是 Java 1.5 的時候引入的功能,它容許方法使用任意多個、類型相同(is-a)的值做爲參數。就像下面這樣。web

public static void main(String[] args) {
    print("沉");
    print("沉""默");
    print("沉""默""王");
    print("沉""默""王""二");
}

public static void print(String... strs) {
    for (String s : strs)
        System.out.print(s);
    System.out.println();
}
複製代碼

靜態方法 print() 就使用了可變參數,因此 print("沉") 能夠,print("沉", "默") 也能夠,甚至 3 個、 4 個或者更多個字符串均可以做爲參數傳遞給 print() 方法。數組

說到可變參數,我想起來阿里巴巴開發手冊上有這樣一條規約。app

意思就是儘可能不要使用可變參數,若是要用的話,可變參數必需要在參數列表的最後一位。既然坑位有限,只能在最後,那麼可變參數就只能有一個(悠着點,悠着點)。若是可變參數不在最後一位,IDE 就會提示對應的錯誤,以下圖所示。spa

那可變參數是怎麼工做的呢?debug

原理也很簡單。當使用可變參數的時候,其實是先建立了一個數組,該數組的大小就是可變參數的個數,而後將參數放入數組當中,再將數組傳遞給被調用的方法日誌

這就是爲何可使用數組做爲參數來調用帶有可變參數的方法的根本緣由。代碼以下所示。code

public static void main(String[] args) {
    print(new String[]{"沉"});
    print(new String[]{"沉""默"});
    print(new String[]{"沉""默""王"});
    print(new String[]{"沉""默""王""二"});
}

public static void print(String... strs) {
    for (String s : strs)
        System.out.print(s);
    System.out.println();
}
複製代碼

那若是方法的參數是一個數組,而後像使用可變參數那樣去調用方法的時候,能行得通嗎?你們感興趣的話,不妨試一試(行不通,噓)。

那通常何時使用可變參數呢?

可變參數,可變參數,顧名思義,當一個方法須要處理任意多個相同類型的對象時,就能夠定義可變參數。Java 中有一個很好的例子,就是 String 類的 format() 方法,就像下面這樣。

System.out.println(String.format("年紀是: %d"18));
System.out.println(String.format("年紀是: %d 名字是: %s"18"沉默王二"));
複製代碼

PS:%d 表示將整數格式化爲 10 進制整數,%s 表示輸出字符串。

若是不使用可變參數,那須要格式化的參數就必須使用「+」號操做符拼接起來了。麻煩也就惹禍上身了。

在實際的項目代碼中,開源包 slf4j.jar 的日誌輸出就常常要用到可變參數(log4j 就無法使用可變參數,日誌中須要記錄多個參數時就痛苦不堪了)。就像下面這樣。

protected Logger logger = LoggerFactory.getLogger(getClass());
logger.debug("名字是{}", mem.getName());
logger.debug("名字是{},年紀是{}", mem.getName(), mem.getAge());
複製代碼

查看源碼就能夠發現,debug() 方法使用的可變參數。

public void debug(String format, Object... arguments);
複製代碼

那在使用可變參數的時候有什麼注意事項嗎?

有的,有的。咱們要避免重載帶有可變參數的方法——這樣很容易讓編譯器陷入自我懷疑中。

public static void main(String[] args) {
    print(null);
}

public static void print(String... strs) {
    for (String a : strs)
        System.out.print(a);
    System.out.println();
}

public static void print(Integer... ints) {
    for (Integer i : ints)
        System.out.print(i);
    System.out.println();
}
複製代碼

這時候,編譯器徹底不知道該調用哪一個 print() 方法,print(String... strs) 仍是 print(Integer... ints),傻傻分不清。

假如真的須要重載帶有可變參數的方法,就必須在調用方法的時候給出明確的指示,不要讓編譯器去猜。

public static void main(String[] args) {
    String [] strs = null;
    print(strs);

    Integer [] ints = null;
    print(ints);
}

public static void print(String... strs) {
}

public static void print(Integer... ints) {
}
複製代碼

上面這段代碼是能夠編譯經過的。由於編譯器知道實參是 String 類型仍是 Integer 類型,只不過爲了運行時不拋出 NullPointerException,兩個 print() 方法的內部要作好判空的操做。


好了,各位讀者朋友們,以上就是本文的所有內容了。能看到這裏的都是最優秀的程序員,升職加薪就是你了👍。若是以爲不過癮,還想看到更多,我再給你們推薦幾篇。

Java 如何獲取數組和字符串的長度?length 仍是 length()?

爲何 Java 字符串是不可變的?

Java 的 substring() 是如何工做的?

如何檢查Java數組中是否包含某個值 ?

原創不易,若是以爲有點用的話,請不要吝嗇你手中點贊的權力;若是想要第一時間看到二哥更新的文章,請掃描下方的二維碼,關注沉默王二公衆號。咱們下篇文章見!

相關文章
相關標籤/搜索