简体   繁体   English

泛型类型推断失败?

[英]Generics type inference fails?

Example A 例A

Study the following snippet: 研究以下片段:

public class ExampleA {
   static class Pair<F,S> { }

   static <F,S> Pair<F,S> anyPair() { return null; }

   static <F,S> void process(Pair<F,S> p1, Pair<F,S> p2) { return; }

   public static void main(String[] args) {
      Pair<String,Integer> p = anyPair();

      process(p, anyPair()); // doesn't compile
   }
}

Can someone explain why type inference works for the assignment to local variable p but not for the second actual parameter to process ? 有人可以解释为什么类型推断适用于局部变量p的赋值但不适用于要process的第二个实际参数吗?


Example B 例B

This is perhaps simpler to understand: 这可能更容易理解:

public class ExampleB {     
   public static <E> void process(Set<E> s1, Set<E> s2) { return; }

   public static void main(String[] args) {
      process(new HashSet<String>(), Collections.emptySet()); // doesn't compile
   }
}

Same question: why doesn't it compile? 同样的问题:为什么不编译?

I'd hope that Collections.emptySet() would just work for ANY parameterized Set type. 我希望Collections.emptySet()只适用于任何参数化的Set类型。

Your second call to anyPair() does not have any way to determine it's types and so it defaults to <Object, Object> . 你对anyPair()第二次调用无法确定它的类型,因此默认为<Object, Object>

The compiler is breaking process(p, anyPair()); 编译器正在破坏process(p, anyPair()); into it's pieces and processing each individually. 进入它的碎片并单独处理每个碎片。 When it does this, it needs to process the arguments first to determine their types, which can then be used when processing process . 当它这样做时,它需要首先处理参数以确定它们的类型,然后可以在处理process时使用它们。

When it goes to process anyPair() there is no type information available for that piece, because it does not know that it is part of process at that point. 当它去处理anyPair() ,没有可用于该片段的类型信息,因为它不知道它是该点的process一部分。 It defaults to <Object, Object> , which then causes a type mismatch when looking at process . 它默认为<Object, Object> ,这会在查看process时导致类型不匹配。

The same thing happens with your second example. 你的第二个例子也发生了同样的事情。 Collections.emptySet() needs to be processed by itself, but has no way of determining the Types needed. Collections.emptySet()需要自己处理,但无法确定所需的类型。

There are 2 ways to solve this: 有两种方法可以解决这个问题:

The first is to give the compiler the information it needs for type inference the same way you did with the first call to anyPair() , by storing it in a temporary variable with the correct type. 第一种方法是为编译器提供类型推断所需的信息,方法与第一次调用anyPair() ,方法是将其存储在具有正确类型的临时变量中。

The second (thanks to @BalusC) is to use ExampleA.<String, Integer>anyPair() . 第二个(感谢@BalusC)是使用ExampleA.<String, Integer>anyPair() This syntax explicitly sets the types needed without having to look beyond the invocation. 此语法显式设置所需的类型,而不必超出调用范围。

Why: 为什么:

Collections.emptySet() is trying to infer the type to return. Collections.emptySet()试图推断要返回的类型。 It's unable because E could be Object or String . 它不能,因为E可能是ObjectString Both are valid matches for process. 两者都是进程的有效匹配。 Generic parameters are always invariant by default, not contravariant. 默认情况下,通用参数始终不变,而不是逆变。 That means that Integer extends Number but List<Integer> does not extend List<Number> . 这意味着Integer extends NumberList<Integer> 没有扩展List<Number> It does extend List<? extends Number> 确实扩展了List<? extends Number> List<? extends Number> , however. 但是, List<? extends Number>

Solutions: 解决方案:

Use an assignment to infer the type: 使用赋值来推断类型:

public <E> void process(Set<E> s1, Set<E> s2) { return; }

public void main(String[] args) {
   Set<String> s = Collections.emptySet();  // add this line
   process(new HashSet<String>(), s);
}

Explicitly write the type: 明确写出类型:

public <E> void process(Set<E> s1, Set<E> s2) { return; }

public void main(String[] args) {
   process(new HashSet<String>(), Collections.<String>emptySet()); //notice <String>
}

Allow contravariance explicitly (this is probably not what you want, however): 明确允许逆转(但这可能不是你想要的):

public <E> void process(Set<E> s1, Set<? super E> s2) { // added "super"
  return;
}

public void main(String[] args) {
   process(new HashSet<String>(), Collections.emptySet());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM