在返回集合的接口中使用Java泛型.最佳实践?陷阱?

我今天碰到了一些我发现有问题的代码.这是一个简化的例子(不现实).

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>).其他实现者可以使用任何其他类型参数返回ArrayLists,不是吗?

所以我的问题:这是一个问题吗?我应该重构一下吗?这值得么?有什么好处?如果我在返回类型为原始类型的接口中定义了一个方法,但是该方法的实际实现者返回各种参数化类型,我可以遇到什么样的问题?

最佳答案
如果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.这不仅适用于返回类型的genric类型参数,也适用于返回类型本身.因此,如果接口指定List< Foo> get(),可以将它实现为ArrayList< Foo>得到().

转载注明原文:在返回集合的接口中使用Java泛型.最佳实践?陷阱? - 代码日志