我遇到了以下代码的一个奇怪问题(好吧,不是完全这段代码):
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
),编译器能够推断出正确的协变类型,因为它有两种可供选择的子类型,我相信。但是为什么'编译器不能编译第一个声明,但第二个声明是否正常?
答案 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
它看起来更复杂,因为您有Object
和String
而不是其他级别的泛型类型。