【问题标题】:Ambiguity in method invocation, with arguments type of Character and float方法调用中的歧义,参数类型为 Character 和 float
【发布时间】:2021-09-24 00:22:33
【问题描述】:
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');

为什么会出现这样的错误?

【问题讨论】:

    标签: java char character


    【解决方案1】:

    为什么over_Var(1, 'm'); 不模棱两可

    1 是一个整数。它不能直接传递给Characterchar 类型的参数(没有强制转换),所以唯一的选择是(float, Character...) 重载。 确实存在intfloat的扩大原语转换,这在invocation context中是允许的。

    您可能认为1 可以转换为Character,因为您可以在assignment contexts 中执行此操作。

    Character a = 1;
    

    但是,这纯粹是因为在 JLS 的“分配上下文”部分(见上面的链接),有这部分开始:

    此外,如果表达式是 byteshortcharint 类型的常量表达式(第 15.28 节):

    [...]

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

    为什么over_Var('k', 'm'); 不明确

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

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

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

    为什么更改为char 有效

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

    • doublefloat 的超类型

    • floatlong 的超类型

    • longint 的超类型

    • intchar 的超类型

    • intshort 的超类型

    • shortbyte 的超类型

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

    解决歧义的一些方法

    要拨打(float, Character...),您只需投射:

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

    要调用(Character...),您可以传入Character[]

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

    【讨论】:

      【解决方案2】:

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

      如果多个成员方法既可访问又适用于方法调用……Java 编程语言使用选择最具体方法的规则。

      java 编译器不认为其中任何一个更具体,因此方法不明确调用错误

      首先...为什么要在字符和浮点数之间建立联系?

      这与字符在 Java 中的底层工作方式有关。

      例子:

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

      应该返回:

      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 + float = 没有歧义? 我会给你留下“奇怪”这个词

      编辑:这样做的原因(请参阅 Sweeper 的更好答案),是它知道将 char 优先于 float,因为它们是相关类型; char 是浮点数的子类型。另一方面,字符不相关。 (换句话说,明显缺乏“传递性”的原因是特异性只能在被比较的类型的上下文中评估。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-20
        相关资源
        最近更新 更多