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

发布于 2024-08-21 04:32:55 字数 1418 浏览 5 评论 0原文

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

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,不是吗?

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

I ran into some code today that I found questionable. Here's a simplified example (not realistic).

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);
}

Then there's an implementor like so:

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;
      }
}

Ignore any implementation problems you may find in that (I found a few too). What I'm getting at is that the interface does not use any generic type parameter for ArrayList (i.e ArrayList<?>), but the implementor of the interface's method does (i.e. ArrayList<GroceryList>). Other implementors may return ArrayLists with any other type parameters, no?

So my questions: Is this a problem? Should I refactor anything? Is it worth it? What's the advantage? What kind of problems can I run into if I have a method defined in an interface whose return type is a raw type, but the actual implementors of the method return various parameterized types?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

愿得七秒忆 2024-08-28 04:32:55

如果 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; get(),可以将其实现为 ArrayList;获取()。

if both methods of IListable always return the same type, use this instead:

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);
}

if this isn't an option, try using ? instead. While it's basically the same, it avoids ugly warnings.

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);
}

Generally, it's not a problem to use a more specific return type in an implementation than in a super-type or interface. If you're dealing with IListable, you need to handle any object type in the returned list. If you're dealing with GroceryList, you expect only GroceryItems. That's not only true for genric type arguments of return types, but for the return type itself as well. So if an interface specifies List<Foo> get(), is okay to implement it as ArrayList<Foo> get().

墨小墨 2024-08-28 04:32:55

最佳实践是永远不要在 Open 代码中返回带有 pure 通配符的 List,就像不应该返回 一样空

Java 中的通配符泛型会给所有使用你的代码的程序员带来污染。您可以在Close代码中执行此操作来解决本地问题。

通常,您将避免返回协变和逆变通配符,例如 ListList

如果您知道自己在做什么并阅读有关 PECS有界通配符不要仅仅因为它可以编译就这样做。

Best practice is to never return a List<?> with pure wildcard in your Open code, just like you should not return null.

Wildcard generics in Java will bring contamination to all coders using your code. You can do it in your Close code to resolve local problem.

Usually, you will avoid to return covariance and contravariance wildcards like List<? extends User> and List<? super User>

You can do it if you know what you are doing and read everything about PECS, and bounded wildcards. Don't do it only because it compiles.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文