關(guān)于 Java 的可變參數(shù),你真的了解嗎?
本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲Tang。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。
我們都知道 Java 支持可變參數(shù)的形式定義方法,這種語法糖在某些時(shí)候可以簡化我們的代碼,但是關(guān)于可變參數(shù)是如何實(shí)現(xiàn)的以及其他的更多細(xì)節(jié),你真的知道嗎?今天阿粉就帶你來了解一下。
可變參數(shù)方法的定義
首先看下可變參數(shù)方法在代碼上是如何定義的,如下所示:
- public static void method1(Integer id, String... names) {
- System.out.println("id:" + id + " names:" + names.length);
- }
通過上面的示例,我們可以看出在定義方法時(shí),在最后一個(gè)形參類型后加上三點(diǎn) …,就表示該形參可以接受多個(gè)相同類型的參數(shù)值,多個(gè)參數(shù)值被當(dāng)成數(shù)組傳入。這里我們需要注意幾個(gè)點(diǎn):
- 可變參數(shù)只能作為函數(shù)的最后一個(gè)參數(shù),在其前面可以有也可以沒有任何其他參數(shù);
- 由于可變參數(shù)必須是最后一個(gè)參數(shù),所以一個(gè)函數(shù)最多只能有一個(gè)可變參數(shù);
- Java 的可變參數(shù),會(huì)被編譯器轉(zhuǎn)型為一個(gè)數(shù)組;
上面提到可變參數(shù)的形式會(huì)被編譯成一個(gè)數(shù)組,那么問題來了,我可不可以寫兩個(gè)下面這樣的方法呢?
- public static void method1(Integer id, String... names) {
- System.out.println("id:" + id + " names:"+ names.length);
- }
- public static void method1(Integer id, String[] names) {
- System.out.println("id:" + id + " names:" + names.length);
- }
在一個(gè)類中的定義相同名字的一個(gè)可變參數(shù)的方法和一個(gè)包含數(shù)組的方法,寫完過后我們就發(fā)現(xiàn) IDEA 已經(jīng)提示我們這種寫法的編譯不了的了。
從這里我們可以知道可變參數(shù)在編譯為字節(jié)碼后,在方法簽名中會(huì)以數(shù)組形態(tài)出現(xiàn)的,導(dǎo)致這兩個(gè)方法的簽名一致的,如果同時(shí)出現(xiàn),是不能編譯通過的。
可變參數(shù)方法的調(diào)用
可變參數(shù)方法的調(diào)用跟其他方法的調(diào)用沒什么區(qū)別,這里要說明的是,我們除了通過可變參數(shù)進(jìn)行調(diào)用之外,還可以通過傳入數(shù)組的形式來進(jìn)行調(diào)用,如下所示:
- public static void main(String[] args) {
- //直接傳遞參數(shù)
- method1(1, "ziyou", "java極客技術(shù)");
- //通過數(shù)組的形式傳遞參數(shù)
- String[] array = new String[]{"ziyou", "Java 極客技術(shù)", "fdf"};
- method1(2, array);
- //不傳遞可變參數(shù)
- method1(3);
- }
通過可變參數(shù)和數(shù)組的形式,這兩種調(diào)用形式本質(zhì)上是一樣的;另外可變參數(shù)的個(gè)數(shù)也可以為 0。
可變參數(shù)方法的重載
試想一下如果我們定義了下面這樣的兩個(gè)方法,定義和使用的時(shí)候會(huì)是什么情況
- public static void method2(String... names) {
- System.out.println("111111");
- }
- public static void method2(String value1, String value2) {
- System.out.println("22222");
- }
第一個(gè)是只有一個(gè)可變參數(shù)形參的方法;第二個(gè)是一個(gè) String 類型的固定參數(shù)和第二個(gè)參數(shù)是可變參數(shù)的方法。首先,定義的時(shí)候完全沒有問題,IDEA 也沒有任何錯(cuò)誤提示,編譯也不會(huì)有問題。
那么在使用的時(shí)候呢?比如下面這樣的寫法會(huì)輸出什么結(jié)果呢?
- public static void main(String[] args) {
- method2("java 極客技術(shù)", "ziyou");
- }
在看輸出結(jié)果之前,我們可以看到,main 函數(shù)中的調(diào)用,其實(shí)這兩個(gè)重載的函數(shù)都是可以滿足的,而且編譯也沒有錯(cuò),那么程序運(yùn)行會(huì)輸出什么呢?
通過實(shí)際的運(yùn)行結(jié)果我們可以看到,輸出的結(jié)果是22222 表示運(yùn)行的是method2(String value1, String value2) 這個(gè)方法,那說明什么問題呢?
說明當(dāng)存在與可變參數(shù)方法形成重載方法的時(shí)候的,會(huì)優(yōu)先固定參數(shù)的方法進(jìn)行執(zhí)行,相信這一點(diǎn)大家應(yīng)該都從來沒有關(guān)注過。
寫到這里可能有小明要問了,那如果我們第二個(gè)方法中的 value2 也是可變參數(shù)呢?那這種情況會(huì)怎么樣呢?為此我們?cè)倏匆幌?,下面的這種形式會(huì)怎樣。
- public static void method2(String... names) {
- System.out.println("111111");
- }
- public static void method2(String value1, String value2) {
- System.out.println("22222");
- }
- public static void method2(String value1, String... value2) {
- System.out.println("33333");
- }
首先定義的時(shí)候 IDEA 沒有任何錯(cuò)誤提示,說明編譯是沒有問題的,那調(diào)用的時(shí)候呢?
可以看到這個(gè)時(shí)候 IDEA 已經(jīng)提示我們匹配到多個(gè)方法合適的方法,不能編譯通過,主要是第一個(gè)和第三個(gè)方式的寫法導(dǎo)致的,匹配到了多個(gè)可變參數(shù)的方法,我們?nèi)粘i_發(fā)的時(shí)候要注意這個(gè)問題。
Object 可變參數(shù)
看到這樣有小明就要問了,那我可不可以創(chuàng)建一個(gè)基于 Object 的可變參數(shù)方法,這樣子這個(gè)方法不就是可以接受所有類型的參數(shù)了嗎?就像這樣:
- public static void method3(Object... objects) {
- System.out.println("objects size" + objects.length);
- }
首先要說的是,這么定義當(dāng)然是沒有問題的,但是可讀性會(huì)差很多,調(diào)用方完全不知道要傳入什么類型;要是真的寫了太多像這樣的代碼,估計(jì)維護(hù)起來也是害人害己,這么寫的小明就好自為之吧,被開除了不要說是看了阿粉寫的文章學(xué)會(huì)的。