泛型-编译器不一致[jdk 1.8.0_162]

时间:2019-01-12 09:47:06

标签: java generics java-8 compiler-errors

我遇到了泛型问题,这让我感到困惑,因为编译器实际上是如何处理泛型类型的。请考虑以下内容:

_bookdown.yml

以下内容将不会编译,因为调用// 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()); } 时,这两种通用类型都被简化为Object

thenComparing

但是,如果我像下面的示例一样分解它们,则所有内容都会正确编译(并运行):

Comparator<A<String, Integer>> c = wrap((L, R) -> Integer.compare(L, R))
    .thenComparing(wrap((L, R) -> Integer.compare(L, R)));

所以问题是:这里会发生什么?我怀疑这是由于编译器的某些奇怪行为而不是预期的语言规范引起的吗?还是我在这里缺少明显的东西?

2 个答案:

答案 0 :(得分:5)

第二次尝试正确编译,因为您自己指定了变量的类型,并告诉编译器它是什么,因为编译器没有足够的信息来找出它。

看看这个简化的示例,它来自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)));
  }
}

答案 1 :(得分:1)

只是使一条中央信息更加可见,即“连锁呼叫”:

采用T t = m1().m2()形式的任何内容,最后一个点剩下的所有内容都将具有有限的类型推断,而没有target type。目标类型T只能帮助推断m2(),而不能m1()

在语言设计中,这是故意选择的选项,目的是避免复杂性。在这种方法中,m1()的类型推断必须在开始为m2() 推断类型之前完成(否则,您将在哪里搜索方法m2?)