2010-02-10 45 views
5

今天我遇到了一些我觉得可疑的代码。这是一个简化的例子(不现实)。在返回集合的接口中使用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,否?

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

+2

除了sfussenegger说的,我还希望方法返回'List'而不是'ArrayList'。 – 2010-02-10 18:41:32

回答

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。这不仅适用于返回类型的genric类型参数,还适用于返回类型本身。所以如果一个接口指定了List<Foo> get(),那么可以将它实现为ArrayList<Foo> get()

+0

此方法还允许您将GroceryList变为完全通用的类型列表,以供日后重用。 – Thirler 2010-02-10 18:09:28

0

最佳做法是永远不会在你的打开代码返回List<?>通配符,就像你不应该返回null

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

通常情况下,你会避免返回协方差和逆变通配符像List<? extends User>List<? super User>

你可以做到这一点,如果你知道你在做什么,关于PECS,并且bounded wildcards读到的一切。 不要只因为它编译。