我们来仔细看看这两个方法, 它们是重载吗? 当然是了, 重载的定义是“方法名相同, 参数类型或数量不同” , 很明显这两个方法是重载。 但是再仔细瞧瞧, 这个重载有点特殊: add(int a,int... b) 的参数范畴覆盖了add(int a,int b)的参数范畴。 那问题就出来了 : 对于 add(int a,int b)这样的计算, 到底该调用哪个方法来处理呢? 我们知道 Java 编译器是很聪明的, 它在编译时会根据方法签名( Method Signature) 来确定调用哪个方法, 比如 add(1,2,3)这个调用, 很明显 2和 3会被转成一个包含两个元素的数组, 并传递到 add(int a,int... b)中, 因为只有这一个方法签名符合该实参类型, 这很容易理解。 但是我们现在面对的是 add(1,2)调用, 这个“2”既可以被编译成 int 类型的“2” , 也可以被编译成 int 数组“{2}” , 即只包含一个元素的数组。 那到底该调用哪一个方法呢? 我们先运行一下看看结果, 运行结果是: c=5.0
public class Client {
public void add(int a,int b) {
float c=a+b+b;
System.out.println("c="+c);
}
public void add(int a,int... b) {
float c=a;
for (int i : b) {
c=c+i;
}
System.out.println("c="+c);
}
public static void main(String[] args) {
Client client=new Client();
client.add(1,2);
}
}
看来是调用了第一个方法, 为什么会调用第一个方法, 而不是第二个变长参数方法呢?因为 Java 在编译时, 首先会根据实参的数量和类型(这里是 2 个实参, 都为 int 类型, 注意没有转成 int 数组) 来进行处理, 也就是查找到add(int a,int b)方法, 而且确认它是否符合方法签名条件。 现在的问题是编译器为什么会首先根据 2 个 int 类型的实参而不是 1 个 int 类型、 1 个 int 数组类型的实参来查找方法呢? 这是个好问题, 也非常好回答 : 因为 int 是一个原生数据类型, 而数组本身是一个对象, 编译器想要“偷懒” , 于是它会从最简单的开始“猜想” , 只要符合编译条件的即可通过, 于是就出现了此问题。 问题是阐述清楚了, 为了让我们的程序更易读,还是慎重考虑变长参数的方法重载吧, 否则让人伤脑筋不说, 说不定哪天就陷入这类小陷阱里了。