Java不定長引數

韓師學子--胖佳發表於2019-03-12

                      Java不定長引數

 

轉載:https://www.msyy233.com/posts/33024.html#more

 

一、不定長引數的基本使用

定義實參個數可變的方法:只要在一個形參的型別與引數名之間加上三個連續的 “.”(即 “…”、英文裡的句中省略號)、就可以讓它和不確定個實參相匹配。
 

public class Main {

    /** 不定長引數方法 */
    static int sumvarargs(int... intArrays) {
        int sum = 0;
        for (int i = 0; i < intArrays.length; i++) {
            sum += intArrays[i];
        }
        return sum;
    }

    public static void main(String args[]) {
        // 呼叫方式一
        int sum1 = sumvarargs(10, 12, 13);

        // 呼叫方式二
        int[] varargs = new int[]{10, 12, 13};
        int sum2 = sumvarargs(varargs);

        // 輸出結果 => sum1:35
        System.out.printf("sum1:%d%n", sum1);

        // 輸出結果 => sum2:35
        System.out.printf("sum2:%d%n", sum2);
    }

}

工作原理:

  1. 以呼叫方傳遞的引數的數目為長度建立一個陣列、
  2. 將實參的值放入陣列中、
  3. 將陣列的引用傳遞給被調方法、

Java原始碼使用例子:String.format(String format, Object... args)

 

二、不定長引數問題和規範

1、呼叫問題和規範

  1. 如果呼叫的方法可以和兩個可變引數匹配、則編譯報錯

     

    public class Main {
    
        static int sumvarargs(int... intArrays) {
            int sum = 0;
            for (int i = 0; i < intArrays.length; i++) {
                sum += intArrays[i];
            }
            return sum;
        }
    
        static int sumvarargs(int intArray, int... intArrays) {
            int sum = intArray;
            for (int i = 0; i < intArrays.length; i++) {
                sum += intArrays[i];
            }
            return sum;
        }
    
        public static void main(String args[]) {
             /*
              下面兩個呼叫都不能編譯通過、
              因為編譯器不知道該選哪個方法呼叫
              */
            int sum1 = sumvarargs(10);
            int sum2 = sumvarargs(10, 12, 13);
            System.out.printf("sum:%d%n", sum1);
            System.out.printf("sum:%d%n", sum2);
        }
    
    }

    如果呼叫可變長引數的過載方法時隱藏了實參型別、也可能發生類似問題一中錯誤、

public class Main {

    static int sumvarargs(String desc, int... intArrays) {
        System.out.println(desc);
        int sum = 0;
        if (intArrays == null)
            return sum;
        for (int i = 0; i < intArrays.length; i++) {
            sum += intArrays[i];
        }
        return sum;
    }

    static int sumvarargs(String desc, String... strArrays) {
        System.out.println(desc);
        int sum = 0;
        if (strArrays == null)
            return sum;
        for (int i = 0; i < strArrays.length; i++) {
            int intArray = Integer.valueOf(strArrays[i]);
            sum += intArray;
        }
        return sum;
    }

    public static void main(String args[]) {
         /*
         下面兩個呼叫都不能編譯通過、
         因為編譯器不知道該選哪個方法呼叫
         */
        int sum1 = sumvarargs("sum");
        int sum2 = sumvarargs("sum", null);

        System.out.printf("sum1:%d%n", sum1);
        System.out.printf("sum2:%d%n", sum2);

    }

}

上面的情況是由於不是很好的編碼習慣造成的、即呼叫者隱藏了實參型別、
避免這種情況的程式碼寫法如下:
 

public class Main {

    static int sumvarargs(String desc, int... intArrays) {
        System.out.println(desc);
        int sum = 0;
        if (intArrays == null)
            return sum;
        for (int i = 0; i < intArrays.length; i++) {
            sum += intArrays[i];
        }
        return sum;
    }

    static int sumvarargs(String desc, String... strArrays) {
        System.out.println(desc);
        int sum = 0;
        if (strArrays == null)
            return sum;
        for (int i = 0; i < strArrays.length; i++) {
            int intArray = Integer.valueOf(strArrays[i]);
            sum += intArray;
        }
        return sum;
    }

    /*
     * 控制檯輸出:
     * 呼叫int不定長方法
     * 呼叫str不定長方法
     * sum1:0
     * sum2:3
     */
    public static void main(String args[]) {

        int[] intArrays = null;
        int sum1 = sumvarargs("呼叫int不定長方法", intArrays);
        int sum2 = sumvarargs("呼叫str不定長方法", new String[]{"1", "2"});

        System.out.printf("sum1:%d%n", sum1);
        System.out.printf("sum2:%d%n", sum2);

    }

}


呼叫的方法能夠和固定引數的方法匹配、也能夠與可變長引數的方法匹配、則選擇固定引數的方法

 public class Main {

     static int sumvarargs(int intArray) {
         return intArray * 2;
     }

     static int sumvarargs(int... intArrays) {
         int sum = 0;
         for (int i = 0; i < intArrays.length; i++) {
             sum += intArrays[i];
         }
         return sum;
     }

     public static void main(String args[]) {

         int sum1 = sumvarargs(10);
         int sum2 = sumvarargs(10, 12, 13);

         // 輸出結果 => sum1:20
         System.out.printf("sum1:%d%n", sum1);

         // 輸出結果 => sum2:35
         System.out.printf("sum2:%d%n", sum2);

     }

 }

2、定義問題和規範

  1. 一個方法只能有一個可變長引數、並且這個可變長引數必須是該方法的最後一個引數
     

     public class Main {
    
         /** 編譯報錯 */
         static void test(String... strs, List list) {}
    
         /** 編譯報錯 */
         static void test(String... strs, List... lists) {}
    
     }

    重寫變長方法也要循規蹈矩

    public class Main {
    
       public static void main(String[] args) {
           // 向上轉型
           Base base = new Sub();
           base.print("hello");
    
           // 不轉型
           Sub sub = new Sub();
           sub.print("hello"); // 此行編譯不通過
       }
    
    }
    
    // 基類
    class Base {
    
       void print(String... args) {
           System.out.println("Base - args[0]:" + args[0]);
       }
    
    }
    
    // 子類,覆寫父類方法
    class Sub extends Base {
    
       @Override
       void print(String[] args) {
           System.out.println("Sub - args[0]:" + args[0]);
       }
    
    }

    第一個能編譯通過、這是為什麼呢?事實上、Base物件把子類物件Sub做了向上轉型、形參列表是由父類決定的、當然能通過、而看看子類直接呼叫的情況、這時編譯器看到子類覆寫了父類的print方法、因此肯定使用子類重新定義的print方法、儘管引數列表不匹配也不會跑到父類再去匹配下、因為找到了就不再找了、因此有了型別不匹配的錯誤。

     

    總結下覆寫必須滿足的條件:

  2. 重寫方法不能縮小訪問許可權

    引數列表必須與被重寫方法相同(包括顯示形式)

    返回型別必須與被重寫方法的相同或是其子類

    重寫方法不能丟擲新的異常、或者超過了父類範圍的異常、但是可以丟擲更少、更有限的異常、或者不丟擲異常

相關文章