繁体   English   中英

为什么像 Collections 类中的 sort 方法不在 List 接口中?

[英]Why methods like sort in Collections class are not in List interface?

类 Collections 有一些静态方法作为实用程序来操作 List 等集合。 例如排序方法 (Collections.sort(list))。 我不明白为什么 Java 规范创建另一个类来承载排序方法(以及所有其他类,如 binarySearch)而不是 List 接口和具体的子类,如 ArrayList 和 LinkedList 实现这些方法。

更新

当我进行了全球研究并阅读了这篇文章的答案时,我不得不说(鸟瞰):有些人(我提到@dan,@WJS,@cdalxndr)在这篇文章中说,以排序方法为例,因为ArrayList和LinkedList的排序可以用同样的方式完成,所以我们可以实现一次只写一次。 所以(我说)我们可以把代码放在 List 接口中,但是直到 Java 7 我们不能把任何实现放在接口的主体中,一次编写它的唯一方法是在实用程序类中实现。 但是由于 Java 8 接口具有“默认”方法的特性。 Java 团队利用这个特性在接口级别实现了 sort 方法,并且该方法可以被 ArrayList 和 LinkedList 使用(如果类没有覆盖它,则作为默认值)

排序是一种算法, List是一个容器。

开发人员希望将列表算法(排序、二分搜索等)与容器逻辑(添加、删除等)分开,因此他们将这些算法放在实用程序类Collections

在 Java 8 之前,接口不能有defaultstatic方法,因此,添加到接口的每个方法都需要由实现该接口的所有类来实现。 即使您在支持类中提供了有用的实现,实现类也至少需要一个委托方法。

因此,除非您想强制所有实现从提供这些方法的某个抽象基类继承,否则您必须小心添加到接口中的内容。

即使使用default方法,您也必须小心,避免使用太多方法污染实现类的名称空间。 这也可能是 Java 8 中并非每个操作都被改造成default方法的原因:

虽然向接口添加default方法的侵入性较小,因为它不需要在已经存在的实现类中实现它,但它仍然可能导致与未实现接口方法的实现类的具体方法发生冲突在以前的版本中。

想象一下 Java 之前 8 次的自定义List实现,它提供了一个有用的void sort(Comparator c)实例方法,只是委托给Collections.sort(this, c); . 这在 Java 8 之前有效,没有提高性能,但允许编写list.sort(c); . 如今,此方法会无意中覆盖具有相同名称和类型的default方法, Collections.sort将委托给该方法,从而产生无限循环(或者更确切地说,递归)。

尽管如此, sort方法已添加到List接口中,因为它具有直接的好处。 Collections实用程序类中的static方法不同, default方法可以被覆盖。 这已针对最常用的列表类型ArrayListVector以及Array.asList(…)返回的实现完成。 由于所有这些实现都由一个数组支持,因此覆盖方法可以直接使用支持数组委托给Arrays.sort ,而default实现将使用列表内容的临时副本。

还值得注意的是, Collections中的这些方法最初似乎是基于这些算法适用于所有类型的实现的假设,但并不成立。 在引入 Collection API 之后的两个版本中,引入了RandomAccess标记接口,以区分两个根本不同的列表实现类别,因此静态方法可以基于它分支到两种替代算法。

每当我们必须基于我们正在操作的类进行分支时,我们可以质疑抽象并说我们最好在类型本身上使用可覆盖的方法,但如上所述,设计有历史原因,并且仍然是在向接口添加方法时要小心的理由。

几分,因为Java的8个选项,只需要你定义(或使用预定义的比较)。

下面的虚拟示例:

    List<Integer> list = new ArrayList();
    list.addAll(List.of(1,5,4,3,6,8,9,2));

    list.sort(Comparator.naturalOrder());

但显然,作为用户,它不像在 Collections util 中那样以相同的方式完成(尽管我确实相信 Collections 实现也使用这样的比较器或类似的东西)。

因为没有必要。 以下所有扩展Collection

BeanContext, BeanContextServices, BlockingDeque<E>, BlockingQueue<E>,<br>
Deque<E>, EventSet, List<E>, NavigableSet<E>, Queue<E>, Set<E>,<br>
SortedSet<E>, TransferQueue<E>

所以你提倡的是,每个接口都为Collections每个方法提供完全相同的实现或者可能是一个方便的方法。 恕我直言,那将是一种代码膨胀。 在前一种情况下,如果发现改进,则需要更改多个实现。

我知道他们在List接口中添加了sort ,也许是因为这是一个常见的要求。 但是我在使用Collections.sort进行排序时从来没有遇到过问题。 可能还有其他我不知道的原因。

但我倾向于认为CollectionsMath类非常相似。 DoubleInteger没有重复的数学函数。 Math类似, Collections是一个utility ,它提供了各种可供相关类使用的静态方法。 当然, Math类不在 Double 或 Integer 等hierarchy ,但其用法非常相似。

集合框架的设计者(主要是在Sun Microsystems工作时的Josh Bloch ),与 Java API 的许多其他部分一样,都着眼于该语言的寿命。 Java 使用@deprecated标签将 API 的维持和演变的概念直接合并到文档支持的语法中。 具体来说,他们预计在发现额外的“容器”操作以添加到CollectionList接口之前,很可能会开发更多的排序和搜索算法。

他们非常清楚接口的变化会给开发团队带来升级需求。 升级要求减缓了 Sun Microsystems 希望团队能够轻松吸收的修复和改进的采用。 将用于排序和搜索的新方法合并到界面中将极大地阻碍该目标; 给选择升级到最新版本 Java 语言的团队带来了不必要的负担。 相反,他们明智地选择将这些实用程序方法分流到静态实用程序类。

与 Java 8 的List.sort(..) ,我只能猜测Oracle感受到了行业和其他语言将这些常见操作直接纳入其集合本身的压力。 但是,将这些实用程序与集合分开可以最大限度地减少它们对直接实现其接口的人施加的采用要求。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM