java泛型中的奇怪类型错误

时间:2012-09-21 15:17:34

标签: java generics

我遇到了以下代码的一个奇怪问题(好吧,不是完全这段代码):

public class CompilationProblems1 {

  static Box<Class<? extends AlcoholicBewerage>> brokenBoxOfOneBeer = boxOf(Beer.class);
  static Box<? extends Class<? extends AlcoholicBewerage>> boxOfOneBeer = boxOf(Beer.class);
  static Box<Class<? extends AlcoholicBewerage>> boxOfBeerAndVodka = boxOf(Beer.class, Vodka.class);

  interface AlcoholicBewerage {}

  class Beer implements AlcoholicBewerage {}

  class Vodka implements AlcoholicBewerage {}

  static class Box<T> {}

  static <E> Box<E> boxOf(E e) {
      return new Box<E>();
  }

  static <E> Box<E> boxOf(E e1, E e2) {
      return new Box<E>();
  }
}

第一个声明brokenBoxOfOneBeer给出了编译错误:

found   : lt.tool.CompilationProblems1.Box<java.lang.Class<lt.tool.CompilationProblems1.Beer>>
required: lt.tool.CompilationProblems1.Box<java.lang.Class<? extends   lt.tool.CompilationProblems1.AlcoholicBewerage>>
static Box<Class<? extends AlcoholicBewerage>> brokenBoxOfOneBeer = boxOf(Beer.class);

这个错误发生在OpenJDK 6,Eclipse和IntelliJ上。我知道这是类型推理器的限制。

在第三种情况下(boxOfBeerAndVodka),编译器能够推断出正确的协变类型,因为它有两种可供选择的子类型,我相信。但是为什么'编译器不能编译第一个声明,但第二个声明是否正常?

2 个答案:

答案 0 :(得分:1)

首先根据实际参数(Beer.class)推断类型参数(§15.12.2.7)。如果无法根据实际参数推断类型参数,则会考虑上下文(brokenBoxOfBeer)。{/ p>

因此,您可以按照以下方式解决此问题。

static <X, E extends X> Box<X> boxOf(E e) {
  return new Box<X>();
}

编辑:我应该注意到这是一种解决方法,并且有一系列问题。将无法再正确推断嵌套调用。

Box<Box<Integer>> x = boxOf(boxOf(1)); // won't compile

答案 1 :(得分:1)

  

但是为什么'编译器不能编译第一个声明,但第二个声明是否正常?

在这两种情况下,表达式boxOf(Beer.class)都有Box<Class<Beer>>类型。

  • 第一个声明需要它具有类型Box<Class<? extends AlcoholicBewerage>>;由于Box<Class<Beer>>不是Box<Class<? extends AlcoholicBewerage>>的子类型,因此无效。 (Class<Beer>Class<? extends AlcoholicBewerage>的子类型,但由于不变性,需要Box<Class<Beer>>Box<Class<? extends AlcoholicBewerage>>的子类型。)< / LI>
  • 第二个声明需要它具有类型Box<? extends Class<? extends AlcoholicBewerage>> - 它的作用。 Class<Beer>Class<? extends AlcoholicBewerage>的子类型,ergo Box<Class<Beer>>Box<? extends Class<? extends AlcoholicBewerage>>的子类型。

也就是说,您的声明中会发生完全相同的事情,如:

List<Object> foo = new ArrayList<String>(); // doesn't work
List<? extends Object> bar = new ArrayList<String>(); // works

它看起来更复杂,因为您有ObjectString而不是其他级别的泛型类型。