建立:
我有一些格式化程序的接口:
interface Formatter<T extends AbstractItem> {
String format(T item);
}
我有一家工厂创建此类格式化程序:
public class Factory {
public static Formatter<? extends AbstractItem> create() {
switch (something) {
case SOMETHING: return new Formatter<SomeItem>() { String format(SomeItem item) {...}};
case SOMETHING_ELSE: return new Formatter<OtherItem>() { String format(OtherItem item){...}};
}
现在,我使用这个工厂来获取格式化程序并使用它:
1: Formatter formatter = Factory.create();
2: for (AbstractItem item : items) {
3: formatter.format(item);
4: }
items
列表仅包含AbstractItem
能够处理的formatter
子类型。问题:
我收到两个警告:
Line 1: Formatter is a raw type. References to generic type Formatter<T> should be parameterized.
Line 3: Type safety: The method format(AbstractItem) belongs to the raw type Formatter. References to generic type Formatter<T> should be parameterized.
OK,所以我尝试修复第一个:我知道工厂返回了
AbstractItem
的后代:1: Formatter<? extends AbstractItem> formatter = Factory.create();
现在,第1行的警告消失了,但是第3行出现了新的错误:
Line 3: The method format(capture#3-of ? extends AbstractItem) in the type Formatter<capture#3-of ? extends AbstractItem> is not applicable for the arguments (AbstractItem).
因此,如果我理解正确,那就抱怨
AbstractItem
不是AbstractItem
的子类型(类型约束<? extends AbstractItem>
中要求)。足够公平,但是AbstractItem
是抽象的,因此我传递给item
的formatter
总是某种类型,可以扩展AbstractItem
...我该如何向编译器解释?现在我的解决方案是使用
@SuppressWarnings
... 最佳答案
通过声明方法
public static Formatter<? extends AbstractItem> create()
您声明此方法的调用者永远不会知道
Formatter
的确切类型;调用者只会知道它是一些Formatter<X>
,其中X
是AbstractItem
或其子类。因此,您无法将任何实例传递给返回的Formatter
,因为您永远不知道格式化程序可以处理哪种X
。在这里取消警告是绝对错误的,编译器会告诉您正确的事情:您的代码不安全。给定
AbstractItem
,Foo
和Bar
两个子类,工厂可以返回Formatter<Foo>
,并且可以将Bar
的实例传递给它的format
方法。语义上存在一个问题,即没有指示符,表明工厂将返回什么
Formatter
以及原因。您可以将其设为返回Formatter<X>
的具体工厂,其中X是具体类型,而不是? extends …
,或者您必须添加参数以向工厂提供提示,例如,需要哪种格式化程序。public static <T extends AbstractItem> Formatter<T> create(Class<T> forItemType)
或者你把它变成
public static Formatter<AbstractItem> create()
指定返回的
Formatter
可以处理各种AbstractItem
。请记住,您仍然可以将AbstractItem
的任何子类传递给Formatter<AbstractItem>
,因为AbstractItem
的子类的每个实例也仍然是AbstractItem
的实例,就像在泛型时代一样。