建立:

我有一些格式化程序的接口:

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是抽象的,因此我传递给itemformatter总是某种类型,可以扩展AbstractItem ...

我该如何向编译器解释?现在我的解决方案是使用@SuppressWarnings ...

最佳答案

通过声明方法

public static Formatter<? extends AbstractItem> create()

您声明此方法的调用者永远不会知道Formatter的确切类型;调用者只会知道它是一些Formatter<X>,其中XAbstractItem或其子类。因此,您无法将任何实例传递给返回的Formatter,因为您永远不知道格式化程序可以处理哪种X

在这里取消警告是绝对错误的,编译器会告诉您正确的事情:您的代码不安全。给定AbstractItemFooBar两个子类,工厂可以返回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的实例,就像在泛型时代一样。

08-03 16:41