在返回集合的接口中使用Java泛型。最佳实践?注意事项?

5

今天我遇到了一些代码,我觉得有些问题。这是一个简化的例子(不真实)。

public interface IListable {
    //returns first n items from list
    public ArrayList getFirstNThings(int n);

    //returns last n items from list
    public ArrayList getLastNThings(int n);
}

然后有一个实现者,如下所示:
public GroceryList implements IListable {
    private ArrayList<GroceryItem> groceries;

    public GroceryList() {
        this.groceries = new ArrayList<GroceryItem>();
    }

    public ArrayList<GroceryItem> getFirstNThings(int n) {
        ArrayList<GroceryItem> firstNThings = new ArrayList<GroceryItem>();
        for (int i=0; i < n; i++) {
            firstNThings.add(this.groceries.get(i));
        }
        return firstNThings
     }

     public ArrayList<GroceryItem> getLastNThings(int n) {
         ArrayList<GroceryItem> lastNThings = new ArrayList<GroceryItem>();
         for (int i=this.groceries.size(); i < this.groceries.size()-n; i--) {
           lastNThings.add(this.groceries.get(i-1);
         }
         return lastNThings;
      }
}

忽略你可能在其中发现的任何实现问题(我也发现了一些)。我的意思是该接口没有使用任何ArrayList的通用类型参数(即ArrayList<?>),但是接口方法的实现者却使用了(即ArrayList<GroceryList>)。其他实现者可能会返回具有任何其他类型参数的ArrayList,对吧?
那么我的问题是:这是一个问题吗?我应该重构任何东西吗?这值得吗?有什么优点?如果我在接口中定义了一个返回类型为原始类型的方法,但实际的实现者返回了各种参数化类型,我可能会遇到什么问题?

2
除了sfussenegger所说的之外,我也更喜欢方法返回List而不是ArrayList - Michael Myers
2个回答

5
如果IListable的两种方法始终返回相同的类型,请改用此方法:
public interface IListable<T> {
  //returns first n items from list
  public ArrayList<T> getFirstNThings(int n);

  //returns last n items from list
  public ArrayList<T> getLastNThings(int n);
}

如果这不是一个选项,尝试使用 ? 代替。虽然它基本上相同,但它避免了丑陋的警告。
public interface IListable {
  //returns first n items from list
  public ArrayList<?> getFirstNThings(int n);

  //returns last n items from list
  public ArrayList<?> getLastNThings(int n);
}

通常情况下,实现类的返回类型比超级类型或接口中规定的类型更为具体并不是问题。如果你正在处理IListable接口,则需要处理返回列表中的任何对象类型。如果你正在处理GroceryList,则只需期望GroceryItems类型。这不仅适用于返回类型的泛型类型参数,也适用于返回类型本身。因此,如果一个接口指定 List<Foo> get(),那么将其实现为 ArrayList<Foo> get() 是可以的。

这种方法还允许您将GroceryList转换为完全通用的类型列表,以便稍后重复使用。 - Thirler

0

最佳实践是在您的开放代码中永远不要返回带有通配符的List<?>,就像您不应该返回null一样。

Java中的通配符泛型将会给使用您代码的所有编码人员带来污染。您可以在您的关闭代码中解决本地问题。

通常,您会避免返回协变和逆变通配符,例如List<? extends User>List<? super User>

如果您知道自己在做什么并阅读了关于PECSbounded wildcards的所有内容,则可以这样做。 不要只因为它可以编译而这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接