集合框架中的接口

我的问题是

接口集有方法add(E e) ,它扩展了接口Collection 。 Interface Collection也有方法add(E e)那么为什么我们在接口Set中需要相同的方法,因为它已经扩展了接口Collection 。 什么目的 ? 我坚持这一点

由于这两个正确答案无法说服你,我会试着解释一下。

接口定义了契约 – 即它们定义了要执行的(和绑定的)实现者,因此您知道无论何时通过接口引用对象,它都具有严格定义的行为,无论其实现的具体程度如何

现在,这份合同分为两部分:

  • 方法签名 – 方法签名是编译器强制执行的元素 – 所有实现者必须符合接口定义的所有方法签名
  • 记录的行为 – 当方法比方法签名更多时,记录特殊行为。 它再次告诉客户端接口对所有实现者的期望,尽管它不会在技术上强制实现者遵守它。

这里有具体的Collection / Set示例:

  • 如果你将一个对象称为Collection ,那么你不知道add任何行为 – 它是否允许重复
  • 如果您将对象称为Set ,则可以确定不允许重复。

这种区别是由重新定义的 add方法的javadoc完成的。

Set.add改进了Collection.add的合约。 来自后者的Javadoc:

支持此操作的集合可能会限制可能添加到此集合的元素。 特别是,某些集合将拒绝添加null元素,而其他集合将对可能添加的元素类型施加限制。 集合类应在其文档中明确指出可以添加哪些元素的任何限制。

这就是在Set.add的Javadoc中Set.add ,它声明例如重复的元素没有被添加到集合中。

更新:合同和接口

(包括并扩展我的评论以完善这个答案。)

方法的契约指定 – 正式或非正式 – 调用者期望提供的内容作为该方法的输入,以及方法调用的保证结果是什么 。 例如,合同可能声明不期望null参数,如果方法传递null参数,它将抛出NullPointerException 。 Collection框架中的方法的Javadoc是此类合同的很好的例子。

请注意,某些语言允许甚至需要合同正式定义 ,因此合同将编译到代码中并主动强制执行运行时 。 埃菲尔就是这样一种语言。 但是,Java没有这样的设施; Javadoc中定义的合同不是正式的 ,甚至没有为它们定义严格的格式。 这些仅用于人类阅读,而不被JVM忽视。 因此, 用Java破解合同可能不会立即引起注意 ,只有在后来出现错误时才会出现。

可以为具体类方法和抽象/接口方法定义合同。 接口的契约(应该)绑定到它的所有实现。 即HashSet.addTreeSet.addLinkedHashSet.add等都必须履行Set.add的合同(并可能进一步完善它)。 根据Set.add的约定Set.add打破了Liskov替换原则 。

据我所知,扩展类应该具有超类指定的相同方法。 至于添加方法之间的差异,我建议你比较相应的add() s的javadoc

  • Set.add(E)
  • Collection.add(E)