Java中的模糊重载

4

我正在学习Java,遇到了一些关于重载的问题。以以下函数为例:

f('a', 'a');

If we have two definition as:

static void f(int i, char j){
    System.out.println("int_char");
}

static void f(double i, char j){
    System.out.println("double_char");
}

没问题。因为所有的第二个参数都完全匹配。但是第一个参数,它们都使用了 widen。对于 char 来说,widen 的顺序是:

char -> int -> long -> float -> double

将char转换成int只需要一步,但是将其转换为double需要四步。因此结果是:

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,因为widen > boxing > 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。

当编译器遇到有歧义的函数时,它是否直接“跳过”其他可能性,而选择可变参数函数(如果有)?

谢谢!


1
这些都在JLS中详细解释了。你有在那里进行彻底的研究吗? - Jim Garrison
@JimGarrison 对不起,我只学了两天的Java。我之前真的不知道那些材料。我正在尝试在那里找到答案。感谢您的建议。 - Sheng
1个回答

2

扩展 > 装箱 > 可变参数 不完全正确。

适当的是扩展 > 装箱和拆箱 > 扩展和装箱/拆箱和可变参数 三者皆可。

在第三步中,三种方法都被允许。

static void f(int i, char j){
    System.out.println("int_char");
}

static void f(double i, char j){
    System.out.println("double_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");
}

当需要使用拳击进行比赛时(因为没有拳击就没有比赛),所有第一个或第二个参数是带或不带拳击的方法都被视为同样优先。因此,第一个不比第二个更好,所以我们无法将它们按优先顺序排列。这会导致歧义。
现在如果以下内容也存在:
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,其中涉及到与Java语言规范相关的技术内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接