【问题标题】:Using Java generics in interfaces that return collections. Best practice? Pitfalls?在返回集合的接口中使用 Java 泛型。最佳实践?陷阱?
【发布时间】:2011-01-15 09:34:18
【问题描述】:

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

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)。其他实现者可能会返回带有任何其他类型参数的 ArrayList,不是吗?

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

【问题讨论】:

  • 除了 sfussenegger 所说的,我也更喜欢返回 List 而不是 ArrayList 的方法。

标签: java generics oop collections interface


【解决方案1】:

最佳做法是永远不要在 Open 代码中返回带有 通配符的 List&lt;?&gt;,就像不应该返回 null 一样。

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

通常,您将避免返回诸如List&lt;? extends User&gt;List&lt;? super User&gt; 之类的协变和逆变通配符

如果您知道自己在做什么并阅读有关PECSbounded wildcards 的所有内容,您就可以做到这一点。 不要仅仅因为它可以编译就这样做。

【讨论】:

    【解决方案2】:

    如果 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&lt;Foo&gt; get(),则可以将其实现为ArrayList&lt;Foo&gt; get()

    【讨论】:

    • 此方法还允许您将 GroceryList 制作成一个完全通用的类型列表以供以后重用。
    猜你喜欢
    • 2010-09-18
    • 2010-10-03
    • 1970-01-01
    • 2018-05-05
    • 1970-01-01
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    相关资源
    最近更新 更多