关闭

Java不定长参数

标签: javajava不定长参数不定长参数varargs
220人阅读 评论(1) 收藏 举报
分类:

在Java5中提供了不定长参数(varargs:variable number of arguments)、也就是在方法定义中可以使用个数不确定的参数、对于同一方法可以使用不同个数的参数调用、下面介绍如何定义不定长参数、以及如何使用不定长参数、


一、不定长参数的基本使用

定义实参个数可变的方法:只要在一个形参的类型与参数名之间加上三个连续的 “.”(即 “…”、英文里的句中省略号)、就可以让它和不确定个实参相匹配。

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);

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

}

工作原理:
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);
        }
    
    }
  2. 如果调用可变长参数的重载方法时隐藏了实参类型、也可能发生类似问题一中错误、

    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);
    
        }
    
    }
  3. 调用的方法能够和固定参数的方法匹配、也能够与可变长参数的方法匹配、则选择固定参数的方法

    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);
    
            System.out.printf("sum1:%d%n", sum1); // 输出结果 => sum1:20
            System.out.printf("sum2:%d%n", sum2); // 输出结果 => sum2:35
    
        }
    
    }

2、定义问题和规范

  1. 一个方法只能有一个可变长参数、并且这个可变长参数必须是该方法的最后一个参数

    public class Main {
    
        /** 编译报错 */
        static void test(String... strs, List list) {}
    
        /** 编译报错 */
        static void test(String... strs, List... lists) {}
    
    }
  2. 重写变长方法也要循规蹈矩

    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方法、尽管参数列表不匹配也不会跑到父类再去匹配下、因为找到了就不再找了、因此有了类型不匹配的错误、

    这是个特例、覆写的方法参数列表竟然可以与父类不相同、这违背了覆写的定义、并且会引发莫名其妙的错误、

    总结下覆写必须满足的条件:

    1. 重写方法不能缩小访问权限
    2. 参数列表必须与被重写方法相同(包括显示形式)
    3. 返回类型必须与被重写方法的相同或是其子类
    4. 重写方法不能抛出新的异常、或者超过了父类范围的异常、但是可以抛出更少、更有限的异常、或者不抛出异常

参考资料:Java中可变长参数的使用及注意事项

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:4027次
    • 积分:147
    • 等级:
    • 排名:千里之外
    • 原创:8篇
    • 转载:4篇
    • 译文:0篇
    • 评论:3条
    最新评论