【问题标题】:The Ambiguous Overloading in JavaJava中的模棱两可的重载
【发布时间】:2013-10-03 04:27:48
【问题描述】:

我正在学习 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");
}

会好的。因为所有第二个参数都完全匹配。但是第一个参数,它们都使用了widen。 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,因为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。

当编译器遇到不明确的函数时,是否直接“跳转”到可变参数函数(如果有)而不考虑任何其他候选?

谢谢!

【问题讨论】:

  • 这一切在JLS中有详细的解释。你在那里彻底研究过这个吗?
  • @JimGarrison 对不起。我刚学 Java 正好两天。我真的不知道以前的材料。我试图在那里找到答案。感谢您的建议。

标签: java overloading


【解决方案1】:

加宽 > 装箱 > 可变参数并不完全正确。

适当的是加宽>装箱和拆箱>加宽和装箱/拆箱和可变参数全部三个。

在第三步中所有三个都被允许。

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 个特定 arg 上的加宽距离按优先顺序“排列”它们。但是下面你不能安排他们。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    • 2011-06-30
    • 1970-01-01
    • 2012-07-14
    • 2019-04-27
    相关资源
    最近更新 更多