考虑以下降低测试用例之间暧昧:方法参照一元静态方法是功能及双功能参数类型
import java.util.AbstractList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
public final class Example {
static class PairList<A, B> {
public void replaceAllSecond(Function<? super B, ? extends B> secondFunction) {}
public void replaceAllSecond(BiFunction<? super A, ? super B, ? extends B> secondFunction) {}
}
static class ImmutableList<E> extends AbstractList<E> {
public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) {return null;}
public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {return null;}
public static <E> ImmutableList<E> copyOf(Iterator<? extends E> elements) {return null;}
public static <E> ImmutableList<E> copyOf(E[] elements) {return null;}
@Override public E get(int index) {return null;}
@Override public int size() {return 0;}
}
public static void foo() {
PairList<Integer, List<Integer>> list = new PairList<>();
list.replaceAllSecond(x -> ImmutableList.copyOf(x)); //accepted
list.replaceAllSecond(ImmutableList::copyOf); //error
}
}
与从Oracle JDK 8u40,调用用的λ的javac编译被接受,但调用传递方法引用被拒绝,并出现以下错误:
Example.java:26: error: reference to replaceAllSecond is ambiguous
list.replaceAllSecond(ImmutableList::copyOf); //error
^
both method replaceAllSecond(Function<? super B,? extends B>) in PairList and method replaceAllSecond(BiFunction<? super A,? super B,? extends B>) in PairList match
where B,A are type-variables:
B extends Object declared in class PairList
A extends Object declared in class PairList
1 error
我不明白为什么超载服用BiFunction
是可能适用在这里。从JLS 15.12.2.1(省略一些子弹):
A member method is potentially applicable to a method invocation if and only if all of the following are true:
- If the member is a fixed arity method with arity n, the arity of the method invocation is equal to n, and for all i (1 ≤ i ≤ n), the i'th argument of the method invocation is potentially compatible, as defined below, with the type of the i'th parameter of the method.
An expression is potentially compatible with a target type according to the following rules:
A method reference expression (§15.13) is potentially compatible with a functional interface type if, where the type's function type arity is n, there exists at least one potentially applicable method for the method reference expression with arity n (§15.13.1), and one of the following is true:
- The method reference expression has the form ReferenceType :: [TypeArguments] Identifier and at least one potentially applicable method is i) static and supports arity n, or ii) not static and supports arity n-1.
正如我解释它,BiFunction
的功能类型元数是2,但copyOf
所有重载是静态的,具有元数1,因此该方法引用不是潜在的兼容与BiFunction
参数,因此replaceAllSecond(BiFunction)
不适用。
我误解了JLS,还是这是一个javac错误? JDK-8026231描述了更新javac以实现该规范,但该错误在2013年第一版Java 8之前(2014年3月)得到了解决。
有趣的是,存在竞争的'copyOf'重载触发错误;如果只有其中一个,它编译。感谢您进一步减少它;在完成JLS的工作之后,我很“好,对于一个SO问题的研究就足够了”。 :) –
@JeffreyBosboom在设计新的API时通常会避免创建仅在已接受的函数接口类型中有区别的重载(即使此类型具有不同的arity),因为这可能会导致方法引用不明确。即使没有这个bug,假设下一个Guava版本将添加ImmutableList.copyOf(无论foo,无论吧)(他们有这样做的道德权利):这可能会破坏现有的代码,它使用你的'PairList.replaceAllSecond (ImmutableList :: copyOf)'。在这种情况下,我使用不同的方法名称。 –