我遇到了泛型问题,这让我对编译器实际如何处理泛型类型感到困惑。请考虑以下事项:
// simple interface to make it a MCVE
static interface A<F, S> {
public F getF();
public S getS();
}
static <V, S> Comparator<A<V, S>> wrap(Comparator<S> c) {
return (L, R) -> c.compare(L.getS(), R.getS());
}
以下将无法编译,因为在调用 thenComparing
时,两种泛型类型都被简化为 Object
:
Comparator<A<String, Integer>> c = wrap((L, R) -> Integer.compare(L, R))
.thenComparing(wrap((L, R) -> Integer.compare(L, R)));
但是如果我像下面的例子那样分解它们,一切都会正确编译(并运行):
Comparator<A<String, Integer>> c = wrap((L, R) -> Integer.compare(L, R));
c = c.thenComparing(wrap((L, R) -> Integer.compare(L, R)));
所以问题是:这里发生了什么?我怀疑这是由于编译器的一些奇怪行为而不是预期的语言规范?还是我在这里遗漏了一些明显的东西?
最佳答案
第二次尝试编译正确,因为你自己指定了一个变量的类型,告诉编译器它是什么,因为编译器没有足够的信息来弄清楚它。
看看这个简化的例子,它来自 vavr
(顺便说一下)。有一个 Try<T>
表示某些操作结果的类。通用参数T
是该结果的类型。有一个静态工厂可以立即创建失败,这意味着我们这里没有结果,但是泛型参数仍然存在:
static <T> Try<T> failure(Throwable exception) {
return new Try.Failure(exception);
}
T
在哪里?从这里来?用法如下所示:
public Try<WeakHashMap> method() {
return Try.failure(new IllegalArgumentException("Some message"));
}
Try<WeakHashMap>
这是我的选择,而不是编译器,您实际上可以在其中放入任何您想要的东西,因为您正在选择类型。
在你的例子中也是一样,Comparator
具有通用参数 String
只是,因为你指定了它并且编译器同意它(就像 Try<WeakHashMap>
)。当你添加一个链式调用时,你迫使编译器自己推断类型,它是 Object
,因为它可能是另一种类型吗?
您还可以做什么(注意 Testing.<String, Integer>wrap
):
public class Testing {
static interface A<F, S> {
public F getF();
public S getS();
}
static <V, S> Comparator<A<V, S>> wrap(Comparator<S> c) {
return (L, R) -> c.compare(L.getS(), R.getS());
}
public static void main(String[] args) {
Comparator<A<String, Integer>> comp = Testing.<String, Integer>wrap((L, R) -> Integer.compare(L, R))
.thenComparing(wrap((L, R) -> Integer.compare(L, R)));
}
}
关于java - 泛型 - 编译器不一致 [jdk 1.8.0_162],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54158402/