方法调用不明确,参数类型为 Character 和 float

Ambiguity in method invocation, with arguments type of Character and float

public class Main {  
    static void over_Var(float a, Character... ab) {
        System.out.println("Method1");
    }
    static void over_Var(Character... ab) {
        System.out.println("Method2");
    }
    public static void main(String[] args) {
        System.out.println("Hello World");
        over_Var(1, 'm');
        over_Var('k', 'm');
    }
}

我收到这样的错误:

Main.java:19: error: reference to over_Var is ambiguous
    over_Var('k', 'm');
    ^
 both method over_Var(float, Character...) in Main and method over_Var(Character...) in Main 
 match 1 error

如果我使用 char 而不是 Character,或者删除行 over_Var('k', 'm');

,代码工作正常

为什么我会收到这样的错误?

这里的问题是不是你有可变长度的参数。这是一个The method X is ambiguous for the type Yerror,解释在link:

If more than one member method is both accessible and applicable to a method invocation … The Java programming language uses the rule that the most specific method is chosen.

java compiler doesn’t consider any of them to be more specific, hence the method ambiguous call error

首先...为什么chars和float之间有联系?

这与字符在 Java 中的工作原理有关。

示例:

System.out.println(200 - 'a'); // subtracting a char from 200
System.out.println(0 - 'a'); // subtracting a char from 0

应该Return:

103
-97

那么解决方法是什么?您指定了一个:将 Character 更改为 char。但为什么会这样呢?您偶然发现了非常有趣的Java行为。以此代码为例:

public class Main {  
    static void over_Var(float a, Character b)   {
        System.out.println("Method1");
    }
    static void over_Var(char a, Character b) {
        System.out.println("Method2");
    }
    static void over_Var(Character a, Character b) {
        System.out.println("Method3");
    }
    public static void main(String[] args) {
        over_Var('k','m');
    }
}
  • 由于 charCharacter 之间的歧义,此 将出现错误

  • 注释掉第一个函数。由于 charCharacter

    之间的歧义,它仍然 有错误
  • 注释掉第二个函数。 它将失败,因为 float 转换为 CharacterCharacter

    之间存在歧义
  • 注释掉第三个函数。它将打印 Method2。它知道 char 优先于 float

这似乎……违反了传递性。 char + Character = 歧义。字符 + 浮点数 = 歧义。但是 char + float = 没有歧义? 留给你一个“怪”字

编辑:这样做的原因(参见 Sweeper 的更好答案)是它知道 char 优先于 float,因为它们是 相关类型 ; char 是 float 的子类型。另一方面, Character 不相关。 (换句话说,明显缺乏“传递性”的原因是特异性只能在被比较的类型的背景下进行评估。)

为什么over_Var(1, 'm');没有歧义

1 是一个整数。它不能直接传递给 Characterchar 类型的参数(不强制转换),因此唯一的选择是 (float, Character...) 重载。 是否 存在 intfloat 加宽基元转换,这在 invocation context.

中是允许的

您可能认为 1 可以转换为 Character,因为您可以在 assignment contexts.[=67 中做到这一点=]

Character a = 1;

然而,这纯粹是因为在 JLS 的“Assignment Contexts”部分(见上文link),有这部分开始:

In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:

[...]

调用上下文部分没有此段。所以在现实中,赋值上下文给予常量表达式(如 1)特殊处理,允许它们被转换为比实际更小的类型。调用上下文不会这样做。

为什么 over_Var('k', 'm'); 有歧义

在这种情况下,两种重载都适用。 'k' 是一个 char,并且在调用上下文中允许从 charfloat 的转换(再次扩大原始转换)。在松散的调用上下文中也允许从 charCharacter 的转换。

如果有多种适用方法,编译器会选择最具体的一种。哪个更具体?嗯,两个调用的第二个参数都是 Character,所以我们只需要考虑第一个参数的类型。一个是 float,另一个是 Character。其中哪一个更具体取决于它们的子类型关系。根据 subtyping rules,它们是不相关的,所以两者都不是更具体,所以你会得到一个编译器错误。

这是对规范 15.12.2 整个部分的简化,强烈建议您自行探索:)

为什么更改为 char 有效

不像floatCharacterfloatchar实际上是相关的!具体来说:

  • double is a super type of float

  • float is a super type of long

  • long is a super type of int

  • int is a super type of char

  • int is a super type of short

  • short is a super type of byte

因此 charfloat 的子类型,因此 over_Var(char...)over_Var(float, char...) 更具体,因此将是首选。

解决歧义的一些方法

要调用 (float, Character...),您只需施放:

over_Var((float) 'k', 'm');

要调用(Character...),你可以传入一个Character[]

over_Var(new Character[] {'k', 'm'});