【问题标题】:Why this method is ambiguous?为什么这种方法是模棱两可的?
【发布时间】:2021-10-16 15:43:28
【问题描述】:

我有两个多态方法,它们将两种类型的类作为输入。

我希望基于对象的流执行两个不同的操作。

相反,他告诉我这个方法是模棱两可的。

不使用流显然有效。 我的目的是使用它们。

我该如何解决?

帮帮我,我不明白。谢谢。

Stream.of(1,"Text").forEach(Test::method);


static void method(Integer i){
    System.out.println("i");
}

static void method(String i){
    System.out.println("s");
}

【问题讨论】:

  • "不使用流显然有效。"我不这么认为。告诉我你将如何“不使用流”并使其工作。

标签: java polymorphism ambiguous method-reference


【解决方案1】:

如果您将流分配给局部变量,您会看到 Stream.of(1,"Text") 的类型是 Stream<Object>

Stream<Object> x = Stream.of(1,"Text");

因此,forEach 所需的方法类型为:

static void method(Object obj){
    System.out.println("Object is: "+obj);
}

如果您使用了Stream.of(1,2)Stream.of("Hello", "Text"),那么方法调用将按照您的预期解决。

【讨论】:

  • 流的类型为Stream&lt;Object&gt;因为您将其分配给Stream&lt;Object&gt; 类型的变量。试试Stream&lt;Serializable&gt; x = Stream.of(1,"Text");Stream&lt;Comparable&lt;?&gt;&gt; x = Stream.of(1,"Text");...
  • @Holger 很好发现 - JDK17 建议 Stream 和 Stream 也是有效的分配。
  • 是的,从 JDK 12 开始
【解决方案2】:

您可以添加一个接受 Object 参数的方法,然后使用这种方法:

import java.util.stream.Stream;

public class Test {
static void method(Object o) {
    if(o instanceof String)
        method((String)o);
    if(o instanceof Integer)
        method((Integer)o);
}

static void method(Integer i) {
    System.out.println("i");
}

static void method(String i) {
    System.out.println("s");
}

public static void main(String[] args) {
    Stream.of(1, "Text").forEach(element -> {
        Test.method( element );
    });
}
}

【讨论】:

    【解决方案3】:

    Java 仅在编译时解决重载问题。您似乎希望Test::method 在迭代1 时解析为method(Integer)(第一次重载),并在迭代"Text" 时解析为method(String)(第二次重载)。这是不可能的,Test::method 只能解决一件事。

    错误信息确实有点令人困惑。问题不在于这两种方法之间存在歧义。问题在于,由于流中既有字符串又有整数,forEach 期望你给它一个可以接受 字符串和整数的方法(或者更准确地说,@987654328 之间的常见超类型@ 和 Integer,因为 Java 中没有联合类型)。

    static void method(Object o){
    
    }
    

    但是您所拥有的method 的重载都不接受字符串和整数。

    要做你想做的事,你必须在运行时检查类型,并手动调用重载:

    Stream.of(1,"Text").forEach(x -> {
        if (x instanceof Integer) {
            method((Integer)x);
        } else if (x instanceof String) {
            method((String)x);
        }
    });
    

    我建议您不要将字符串和整数放在同一个流中。

    如果涉及的类型不是StringInteger,而是你写的类,情况就不同了。因为那样你就可以将method写成一个通用超类中的实例方法。与重载解析不同,选择要运行的实例方法的哪个重写实现在运行时完成。

    class Superclass {
      public void method() {
        
      }
    }
    
    class BaseClass1 extends Superclass {
    
      @Override
      public void method() {
        System.out.println("i");
      }
    }
    
    class BaseClass2 extends Superclass {
    
      @Override
      public void method() {
        System.out.println("s");
      }
    }
    
    // ...
    
    Stream.of(new BaseClass1(), new BaseClass2()).forEach(Superclass::method);
    

    【讨论】:

    • “错误信息确实有点令人困惑”——而且不可重现。 javac 和 Eclipse 都不会产生 OP 发布的错误消息……
    • @Holger Huh,我可以用 IntelliJ 重现它。我想这是 IntelliJ 当时所做的另一件令人困惑的事情。
    • 这很奇怪;据我所知,IntelliJ 没有自己的编译器,但居于其他编译器之上。所以它一定已经编辑了错误反馈。收到错误信息时,您知道使用了哪个编译器和版本吗?
    • @Holger 是的,我想是的。如果您将鼠标悬停在红色下划线上可以看到 OP 的错误,但如果您实际单击绿色运行按钮,它将更改为 javac 将显示的内容。
    • @Holger 我正在使用 IntelliJ 2021.2 CE,构建 #iC-212.4742.92。
    【解决方案4】:

    由于Stream.of(1, "Text", null) 中的元素类型是所有三个参数的公共超类型,因此可以实现一个接受Object 类型参数的方法,以将调用调度到适当的重载methodnull 值也应该处理映射到一些特定的方法):

    Stream.of(1,"Text", null).forEach(Test::method);
    
    static void method(Object o) {
        if (o instanceof Integer) {
            method((Integer) o);
        } else if (o instanceof String || null == o) {
            method((String) o);
        } else {
            method(o.toString());
        }
    }
    

    输出:

    i
    s
    s
    

    关于声明:

    不使用流显然有效。

    这似乎不是真的。

    如果创建并使用原始列表/数组而不是 Stream,则会出现类似问题:

    List list = Arrays.asList(1, "Text", null);
    // list.forEach(Test::method); // fails too, same error as below
    for (int i = 0; i < list.size(); i++) {
        method(list.get(i));
    }
    

    在这种情况下,错误如下所示:

    /Test.java:10: error: no suitable method found for method(Object)
        method(list.get(i));
        ^
        method Test.method(Integer) is not applicable
          (argument mismatch; Object cannot be converted to Integer)
        method Test.method(String) is not applicable
          (argument mismatch; Object cannot be converted to String)
    1 error
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-25
      • 1970-01-01
      • 1970-01-01
      • 2018-06-01
      • 2019-11-28
      • 2018-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多