Java 找不到使用双冒号运算符的正确重载方法

2022-09-04 23:17:45

当使用双冒号运算符来引用重载方法时,Java 似乎无法确定要使用的正确方法。请考虑以下示例:

public class A {
    private void setter(final Number value) { }
    private void setter(final Optional<Number> value) { }
    private void setter2(final Optional<Number> value) { }

    private <T> void useSetter(final Consumer<Optional<T>> a) { }

    private void callMethod() {
        useSetter(this::setter); // Error here
        useSetter(this::setter2);
    }
}

第一次调用 不会编译,并给出以下错误:useSetter

Cannot infer type argument(s) for <T> useSetter(Consumer<Optional<T>>)
The type A does not define setter(Optional<Object>) that is applicable here

但是,第二个调用编译得很好,这意味着问题出在 重载 。只有一个重载是适用的,所以我不明白为什么这不起作用。settersetter

可以通过使用指定参数类型的 lambda 来解决此问题,但这要详细得多。

useSetter((final Optional<Number> v) -> setter(v));

有没有更好的方法来处理这种情况,或者我被困在这个奇怪的怪癖上?


答案 1

编译方法的捕获是 。编译器试图告诉您,它无法强制类型以匹配任何已知的捕获。private <T> void useSetter(final Consumer<Optional<T>> a) { }Optional<Object>

Main.java:12: error: incompatible types: cannot infer type-variable(s) T
        useSetter(this::setter); // Error here
                 ^
    (argument mismatch; invalid method reference
      no suitable method found for setter(Optional<Object>)
          method A.setter(Number) is not applicable
            (argument mismatch; Optional<Object> cannot be converted to Number)
          method A.setter(Optional<Number>) is not applicable
            (argument mismatch; Optional<Object> cannot be converted to Optional<Number>))
  where T is a type-variable:
    T extends Object declared in method <T>useSetter(Consumer<Optional<T>>)

一种解决方案是为泛型参数化可选类型创建一个绑定 using。另一种选择是向编译器暗示一些强制功能。private <T> void setter(final Optional<? super T> value) { }private void setter(final Optional<? super Number> value) { }

class A<T> {
    private void setter(final Number value) { }
    private <T> void setter(final Optional<? super T> value) { }
    private void setter2(final Optional<Number> value) { }

    private <T> void useSetter(final Consumer<Optional<T>> a) { }

    private void callMethod() {
        useSetter(this::setter); // no more error
        useSetter(this::setter2);
    }

    public static void main(String [] args){

    }
}

class B {
    private void setter(final Number value) { }
    private void setter(final Optional<? super Number> value) { }
    private void setter2(final Optional<Number> value) { }

    private <T> void useSetter(final Consumer<Optional<T>> a) { }

    private void callMethod() {
        useSetter(this::setter); // no more error
        useSetter(this::setter2);
    }

    public static void main(String [] args){

    }
}

您可以在此处查看ideone

这两个选项都不是完美的,因为它会通过允许传递来为您的代码引入一些可替代性,但是如果您避免直接使用原始类型,您应该没问题。Optional<Object>


答案 2

推荐