为什么List接口要继承Collection接口?

20

Collection接口有多个方法。List接口扩展了Collection接口,并声明了与Collection接口相同的方法。为什么会这样呢?

举个例子:

interface Collection extends Iterable
{
     public abstract int size();
 public abstract boolean isEmpty();
 public abstract boolean contains(java.lang.Object);
 public abstract java.util.Iterator<E> iterator();
 public abstract java.lang.Object[] toArray();
 public abstract <T extends java/lang/Object> T[] toArray(T[]);
 public abstract boolean add(E);
 public abstract boolean remove(java.lang.Object);
 public abstract boolean containsAll(java.util.Collection<?>);
 public abstract boolean addAll(java.util.Collection<? extends E>);
 public abstract boolean removeAll(java.util.Collection<?>);
 public abstract boolean retainAll(java.util.Collection<?>);
 public abstract void clear();
 public abstract boolean equals(java.lang.Object);
 public abstract int hashCode();
}

同样的方法也存在于List接口中:

public interface List extends Collection
{
 public abstract int size();
 public abstract boolean isEmpty();
 public abstract boolean contains(java.lang.Object);
 public abstract java.util.Iterator<E> iterator();
 public abstract java.lang.Object[] toArray();
 public abstract <T extends java/lang/Object> T[] toArray(T[]);
 public abstract boolean add(E);
 public abstract boolean remove(java.lang.Object);
 public abstract boolean containsAll(java.util.Collection<?>);
 public abstract boolean addAll(java.util.Collection<? extends E>);
 public abstract boolean removeAll(java.util.Collection<?>);
 public abstract boolean retainAll(java.util.Collection<?>);
 public abstract void clear();
 public abstract boolean equals(java.lang.Object);
 public abstract int hashCode();
}

如果List已经扩展了Collection接口,那么是否需要在List中重新编写这些方法?


1
我猜只是为了确保可读性。 - Ankur Shanbhag
你在哪里看到的? - Oswald
你从哪里阅读这篇文章的?你在某个地方反汇编了一个.class文件吗? - chrylis -cautiouslyoptimistic-
在Eclipse中使用Ctrl-Shift-T(打开类型)“List”。您应该知道如何快速找到您使用的任何类型的源代码。 - Thomas W
我认为你的标题有误导性。它问的是为什么List扩展了Collection。但实际上问题不同。结果,许多答案回答了标题而不是实际问题。噪音会引起更多的噪音。感谢你做到了这一点。 - Val
8个回答

30

它们被重新编写以便可以进行文档化,以指定列表如何相对于集合接口中指定的契约来细化这些方法的契约。

例如,在List中文档记录的add()方法指定元素添加到列表的末尾。而在集合中无法指定此内容,因为集合没有起点和终点。


2
很好的回答,特别是带有List.add()合同的示例。 - Thomas W

14

随着您向下移动继承层级,JavaDoc和API合约会略有变化或变得更加具体。

List重新声明这些方法并提供更具体的JavaDoc。


这可能不是OP想要的;他正在查看反汇编(请注意java/lang/Object签名),但它被他使用的任何工具组合。 - chrylis -cautiouslyoptimistic-
我的问题是,列表应该只包含那些实现已更改或具有某些不同行为的方法,在这里它写了Collection的所有方法,那么Collection的用途是什么? - user2602839
但是在这里,您可以看到我们正在违反继承规则,即我们在List中再次编写了相同的方法,那么在List中扩展集合有什么用呢? - user2602839
1
@user2602839,您所看到的是编译后类的内部系统表示,而不是接口实际源代码,因此请不要从超级接口方法的重复中得出结论;这是自动生成的。 - chrylis -cautiouslyoptimistic-
1
@user2602839,这个规则是关于复制实现的,List和Collection只声明方法而不提供实现。 - josefx
显示剩余3条评论

6

仅为方便。

文档中提到了相同内容

List接口对于迭代器、添加、删除、相等性和哈希码方法的规约,除了在Collection接口中指定的规约之外,还有额外的规定。这里也为方便起见包括了其他继承方法的声明。


3

Collection<T>是一组项目,本身除了持有其成员的引用外,并没有更多的要求。

在基本的java api中,有两种主要类型的集合:List<T>Set<T>

List<T>有额外的要求,必须为其所有项维护特定的顺序(插入顺序、排序顺序等)。因此,如果您请求N项,则列表将始终返回相同的N项。

Set<T>不保证顺序,但保证项的唯一性。项A不能添加到Set两次,或者只会出现一次。

您应该熟悉“标记”接口的实践。 Serializable就是其中之一,并且通常是谈论此问题时的基本示例。而List<T>Set<T>也被声明为这样的接口,它们将集合标记为一个或另一个,以便告知程序员他们可以从所接收的集合中期望什么行为。

请参考《Effective Java》第6章第37条,详细解释了这比使用注释更好的原因。

还有一个事实,myCollection instanceof MyInterfacemyCollection.getClass().isAnnotationPresent(MyAnnotation.class)myCollection.getClass().getAnnotation(MyAnnotation.class) != null更快。


2
toArray方法的签名表明您从已编译的.class文件中提取了它。根据类文件格式规范.class文件不会重复继承自超级接口的方法,因此我怀疑您使用的工具向您展示了一个组合视图;这些方法实际上并不存在于List上。请注意保留HTML标签。

是的,你说得对 - abstract 修饰符确实表明他是从反编译的类文件中查看的。感谢你的见解! - Thomas W

2
一个集合只是一组项目的集合。 列表除了包含项目列表外,还添加了有关其顺序的信息。
当您向集合添加一个项目时,您只是将其添加进去。 当您向列表添加一个项目时,可以在位置n处添加。
当您从集合中删除项目时,您只是将其删除。 当您从列表中删除项目时,可以在位置n处删除。
当您想从集合中获取一个项目时,您必须进行迭代。 当您想从列表中获取一个项目时,可以在位置n处获取。

先生,我们正在执行实现List接口和Collection接口的类中编写的所有操作。但是在接口的情况下,只有在扩展时我们才不会再次编写相同的方法声明,因为为了可重用性,我们将集合接口扩展到列表接口中。 - user2602839
@user2602839 我想表达的是,通过在“List”中重新声明这些方法,可以带出更具体的行为。 - Vikas V
如果你看到add方法的写法是"public abstract boolean add(E)",并且这个方法在List和Collection中都有定义,那么我们是否违反了继承规则? - user2602839

1

主要是为了文档目的,他们才使用了这样的方式。

例如

Collection#retainAll 

仅保留此集合中包含在指定集合中的元素(可选操作)。

List#retainAll

仅保留此列表中包含在指定集合中的元素(可选操作)。

仅用于Java文档目的,但其中一些方法的行为已经改变。

For ex.add,remove

方法 remove
In List, Removes the first occurrence of the specified element from this list, if it is present (optional operation).

In Collection , Removes a single instance of the specified element from this collection, if it is present (optional operation).

通过Java文档,他们清楚地表明了List实现是有序的。

1
首先,接口List继承了所有Collection方法,因此在Collection接口中存在的所有方法也将存在于List接口中,但List接口具有额外的方法(请自行检查),这些方法描述了列表的行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接