代码之家  ›  专栏  ›  技术社区  ›  n247s

泛型-编译器不一致[JDK 1.8.0 U 162]

  •  6
  • n247s  · 技术社区  · 6 年前

    我遇到了一个关于泛型的问题,这使我对编译器实际上如何处理泛型类型感到困惑。考虑以下事项:

    // 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)));
    

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

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

    所以问题是: 这里发生了什么? 我怀疑这是由于编译器的一些奇怪行为,而不是预期的语言规范?或者我错过了一些明显的东西?

    2 回复  |  直到 6 年前
        1
  •  5
  •   Naman    6 年前

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

    看看这个简化的例子,它来自 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 只有,因为您指定了它,编译器同意它(就像 尝试<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)));
      }
    }
    
        2
  •  1
  •   Stephan Herrmann    6 年前

    只是为了让一个中心信息更加可见,“链接呼叫”:

    任何形式的 T t = m1().m2() 最后一个点的左边的所有内容都有有限的类型推断,没有 target type . 目标类型 T 只能帮助推断 m2() 不是 m1() .

    在语言设计中,这是一个深思熟虑的选择,以避免复杂性。在这种方法中,推断 M1() 必须在开始推断的类型之前完成 M2() (否则,您将在哪里搜索方法m2?) .