9

尝试编译表达式Comparator.comparing(String::toLowerCase)时,Java 编译器返回错误。有关详细信息,请参阅以下问题:

为什么 Comparator.comparing 不适用于 String::toLowerCase 方法参考?


我试图尽可能地减少这个问题。特别是,我已经删除了几乎所有对其他类的依赖。main方法包含两个方法调用。第一条语句编译没有错误,而第二条语句产生错误。

interface Fun<T, R> { R apply(T t); }

public final class Foo {
    public static void main(String... args) {
        invoke(Foo::bar); // OK
        invoke(Foo::baz); // ERROR
    }
    private static <T, U> void invoke(Fun<T, U> f) { }
    private String bar() { return null; }
    private String baz() { return null; }
    private String baz(Integer i, Integer j) { return null; }
}

这很奇怪,因为第二个baz方法不应该在这种情况下适用,因为参数数量不匹配。我看过 JLS8 (15.13)。然而,这并没有帮助,因为方法引用的规则非常复杂。

Q:为什么第二种情况会出现编译错误?根据 JLS,真的应该存在编译错误吗?根据对另一个问题的一些评论,Netbeans 中没有编译错误。


作为参考,我使用的是 JDK8 版本 1.8.0-b132。如果在命令行上编译程序,编译器会显示以下错误消息:

$ /opt/jdk8/bin/javac Foo.java
Foo.java:6: error: incompatible types: cannot infer type-variable(s) T,U
        invoke(Foo::baz); // ERROR
              ^
    (argument mismatch; invalid method reference
      no suitable method found for baz(Object)
          method Foo.baz() is not applicable
            (actual and formal argument lists differ in length)
          method Foo.baz(Integer,Integer) is not applicable
            (actual and formal argument lists differ in length))
  where T,U are type-variables:
    T extends Object declared in method <T,U>invoke(Fun<T,U>)
    U extends Object declared in method <T,U>invoke(Fun<T,U>)
Foo.java:6: error: invalid method reference
        invoke(Foo::baz); // ERROR
               ^
  non-static method baz() cannot be referenced from a static context
2 errors
4

1 回答 1

5

JLS8 (15.13)令人困惑,但它确实显示了与您类似的示例,说明它们在搜索中存在歧义,无法解决。

对于您的示例,Intellij 说invoke(Foo::baz);的是循环推理我认为这与invoke需要推断类型以及Foo::baz.

这可以通过给invoke函数一个类型来解决,类似于 JSL(15.13.1 示例)

搜索足够聪明,可以忽略所有适用方法(来自两个搜索)都是实例方法的歧义:

Foo.<Foo,String>invoke(Foo::baz);-- 相当于,我想使用返回voidFooStringaka的方法String baz()

interface Fun<T, R> { R apply(T t); }
interface Fun2<T,U,R> { R apply(T t, U u); }

public final class Foo {
    public static void main(String... args) {
        invoke(Foo::bar); // OK
        Foo.<Foo,String>invoke(Foo::baz); // NO ERROR
        Fun2<Foo, Integer, String> f2 = Foo::baz; // Overloaded method baz
    }
    private static <T, U> void invoke(Fun<T, U> f) { }
    private String bar() { return null; }
    private String baz() { return null; }
    private String baz(Integer i) { return null; } 
}

我同意你baz(Integer i)的观点,如果不将其设为invoke静态或从Foo. 我猜如果方法重载并且它试图推断类型,搜索算法就会退出。因为它只使用一个方法签名。

于 2014-04-08T22:15:56.000 回答