当使用双冒号运算符引用重载方法时,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
但是,第二个调用编译得很好,这意味着问题出在setter
的重载上。只有setter
超载中的一个适用,因此我不明白为什么这不起作用。
可以通过使用指定参数类型的lambda来解决这个问题,但这更详细。
useSetter((final Optional<Number> v) -> setter(v));
有没有更好的方法来处理这种情况,还是我不能解决这个奇怪的怪癖?
答案 0 :(得分:3)
汇编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>>)
一种解决方案是使用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 here。
这两个选项都不是完美的,因为它会通过允许传递Optional<Object>
来为您的代码引入一些可替代性,但是如果您避免直接使用原始类型,那么应该没问题。