我正在学习 Java,遇到了一些关于重载的问题。以下面的函数使用为例:
f('a', 'a');
如果我们有两个定义:
static void f(int i, char j){
System.out.println("int_char");
}
static void f(double i, char j){
System.out.println("double_char");
}
会没事的。因为所有第二个参数都完全匹配。但是第一个参数,它们都使用了加宽。 char 的扩展顺序是:
char -> int -> long -> float -> double
char要实现int,需要一步。但要实现双倍,则需要 4 个步骤。所以结果是:
int_char
但是我将参数的顺序更改为:
static void f(int i, char j){
System.out.println("int_char");
}
static void f(char i, double j){
System.out.println("char_double");
}
编译器会提出一个不明确的错误。为什么?
另一种情况如下:
static void f(char i, Character j){
System.out.println("char_Character");
}
static void f(Character i, Character j){
System.out.println("Character_Character");
}
第二个参数都使用自动装箱。但是 void f(char i, Character j) 的第一个参数是完全匹配的。为什么这两个函数放在一起会导致歧义?
最后,如果这些函数中的任何一个与以下函数一起出现:
static void f(Character... i){
System.out.println("Character_varargs");
}
输出不是 Character_varargs,因为加宽 > 装箱 > 可变参数。但是当两个模棱两可的函数与 Character_varargs 一起使用时,例如:
static void f(char i, Character j){
System.out.println("char_Character");
}
static void f(Character i, Character j){
System.out.println("Character_Character");
}
static void f(Character... i){
System.out.println("Character_varargs");
}
结果将是 Character_varargs。为什么?
甚至我们添加了一些非歧义和更高优先级的重载函数,例如:
static void f(int i, char j){
System.out.println("int_char");
}
static void f(char i, double j){
System.out.println("char_double");
}
static void f(int i, double j){
System.out.println("int_double");
}
static void f(Character... i){
System.out.println("Character_varargs");
}
结果仍然是 Character_varargs。为什么?如果只考虑 void f(int i, double j) 和 void f(Character... i),输出应该是 int_double。
当编译器遇到不明确的函数时,它是否直接“跳转”到 varargs 函数(如果有)而不考虑任何其他候选函数?
谢谢!
最佳答案
Widen > boxing > varargs 并不完全正确。
适当的是加宽 > 装箱和拆箱 > 加宽和装箱/拆箱和可变参数所有三个。
在第三步中,所有三个都被允许。
static void f(int i, char j){
System.out.println("int_char");
}
static void f(double i, char j){
System.out.println("double_char");
}
在上述情况下,您可以根据 1 个特定参数的加宽距离按偏好顺序“排列”它们。但在下面你不能安排它们。
static void f(int i, char j){
System.out.println("int_char");
}
static void f(char i, double j){
System.out.println("char_double");
}
下一个问题是
static void f(char i, Character j){
System.out.println("char_Character");
}
static void f(Character i, Character j){
System.out.println("Character_Character");
}
当需要允许装箱进行匹配时,(因为没有装箱就没有匹配),所有在第一个或第二个参数上有或没有装箱的方法都以相同的优先级处理。所以第一个并不比第二个好,所以我们不能按优先顺序排列它们。导致歧义。
现在如果下面也存在,
static void f(Character... i){
System.out.println("Character_varargs");
}
根据规则,由于在装箱/拆箱后没有找到合适的方法(找到 2 个不明确的方法),因此需要使用 var args 进行第三步。最终找到了要解决的方法。
在下面的情况下,我们还需要转到第三步(加宽和装箱/拆箱和可变参数)以找到匹配项
static void f(int i, char j){
System.out.println("int_char");
}
static void f(char i, double j){
System.out.println("char_double");
}
static void f(int i, double j){
System.out.println("int_double");
}
static void f(Character... i){
System.out.println("Character_varargs");
}
引用 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12