【问题标题】:Java: Set interface and Collection interface differencesJava:Set接口和Collection接口的区别
【发布时间】:2011-04-28 01:45:15
【问题描述】:

我刚刚查看了Set 接口,发现它大部分(或完全)只重新声明了已经在Collection 接口中的函数。 Set 本身扩展了Collection,那是不是意味着Set 接口自动拥有Collection 的所有功能?那么为什么要重新声明呢?

例如,Set 重新声明:

/**
 * Returns the number of elements in this set (its cardinality).  If this
 * set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
 * <tt>Integer.MAX_VALUE</tt>.
 *
 * @return the number of elements in this set (its cardinality)
 */
int size();

/**
 * Returns <tt>true</tt> if this set contains no elements.
 *
 * @return <tt>true</tt> if this set contains no elements
 */
boolean isEmpty();

还有Collection中的声明:

/**
 * Returns the number of elements in this collection.  If this collection
 * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
 * <tt>Integer.MAX_VALUE</tt>.
 *
 * @return the number of elements in this collection
 */
int size();

/**
 * Returns <tt>true</tt> if this collection contains no elements.
 *
 * @return <tt>true</tt> if this collection contains no elements
 */
boolean isEmpty();

这对我来说似乎很多余。为什么不直接将Set 接口定义为:

public interface Set<E> extends Collection<E> {}

我认为这些接口之间没有单一的区别,对吧?


当然,我不是在问Set 的不同语义/含义。我知道。我只是在问它在技术上(即对编译器)是否有任何区别。即,笼统地说:

interface A { void foo(); }
interface B extends A { void foo(); }
interface C extends A {}

现在,ABC 之间有什么区别吗?


虽然合同(即文档中所说的)对于某些功能(如add)确实可能有所不同,但重新声明它们是有正当理由的:为了能够放置新文档,即定义新合同。

但是,也有一些函数(如isEmpty)具有完全相同的文档/合同。为什么还要重新声明?

【问题讨论】:

  • 我会进行绝食,直到这件事情得到解决!
  • 你要明白界面没有灵丹妙药。在接口中,您无法理解序列,也无法理解 java 中任何类所拥有的不变量。这个问题是一个开放的问题,Java 开发人员决定通过在手册中说明答案来解决。如果你有更好的解决方案,用语言语法表示序列和不变量,这里是一个说明它的地方。
  • @none:嗯,这并不是我提出问题的目的,但这确实是另一个非常有趣的问题。我看到了一些建议,可以为函数编写复杂的逻辑前置条件和后置条件。不过我已经不记得它叫什么了。
  • @pre 和@post 的问题在于它们不会让您知道指令的顺序。让我们简单看一下迭代器模式,他们必须制作一个特殊的语法以使所有人都清楚,并确保正确调用 hasNext() 和 Next() 接口。那么解决方案是通过提供手册并为每个问题创建新的语言语法吗? lisp 是答案(你写的代码写的代码……)我希望不是。

标签: java collections interface set


【解决方案1】:

从技术上讲,对于编译器来说,它根本没有区别。

但是,集合不能有重复的条目,而集合可以。这是值得了解的。

正因为如此,参数、返回值和发生的事情的方法语义可能意味着不同的东西。重新声明还允许 javadoc 变得更加具体。例如对于 add():

Set: @return 如果这个 set 还没有包含指定的元素,则返回 true

Collection: @return true 如果此集合因调用而改变

set的含义更具体。

即使对于不是更具体的方法,它也能使 javadoc 更好。例如,对于 size() :“返回此集合中的元素数(其基数)。”这更接近人们习惯于数学集合所理解的语言。

API 文档对此进行了总结:“Set 接口对所有构造函数的合约以及 add、equals 和 hashCode 方法的合约进行了额外的规定,超出了从 Collection 接口继承的规定。声明为方便起见,此处还包括了其他继承方法。(这些声明随附的规范已针对 Set 接口进行了定制,但它们不包含任何附加规定。)"

【讨论】:

  • 我认为这不是问题所在。问题是为什么要重新声明相同的方法(例如 sizeisEmpty)。
  • @musiKk - 谢谢,我想我已经提到过,但我现在试着更具体一些
  • 啊,所以,主要原因(对于大多数功能)和我的问题的基本答案是:“它使 javadoc 更好”:) 这是我假设的,但我在这里问只是为了确定这一点。
  • @Albert:这不仅仅是让 Javadoc 变得更好......语义上的差异产生了功能上的差异,并且拥有一个表示 Set 的单独接口使您能够限制给定的方法工作只有通过简单地将 Set 而不是 Collection 声明为参数类型,以类型安全的方式遵守 Set 语义的集合。
  • @ColinD:我知道不同的含义。但是编译器仍然没有区别。 IE。只是 Javadoc 不同。
【解决方案2】:

答案在用于 set 的 java6 API 中。

“除了从 Collection 接口继承的那些之外,Set 接口对所有构造函数的合约以及 add、equals 和 hashCode 方法的合约进行了额外的规定。为方便起见,此处还包括其他继承方法的声明。 (这些声明随附的规范已针对 Set 接口进行了定制,但它们不包含任何额外的规定。)"

【讨论】:

  • 啊,不知何故读多了。但只是澄清一下:从技术上讲,它没有任何区别吗?只是 IDE 向开发者展示的某些功能的文档有些不同?
  • @Albert 有什么不同?世界上各有不同,因为 Set 语义不同,Collection 语义不同于 List 语义等等。
  • @hvgotcodes:技术差异 = 如果您使用我的 Set 定义,现有的工作代码将会中断
  • @albert,对不起,我没有关注你。接口没有被逐字复制,它正在被重新定义;即扩展以考虑集合的不同之处。
  • 我的问题是:如果你用我给定的建议替换Set 的定义,现有的工作代码会中断吗?
【解决方案3】:

方法不仅仅是它的签名。

在这种情况下,这些方法的文档已根据前置条件和后置条件以及术语针对集合进行了定制。

【讨论】:

    【解决方案4】:

    重新声明它们是因为即使名称相同,它们的含义也不同。 Set 中的add 方法是Collection 中通用add 方法的特定实现。

    目的是明确指定Setadd 方法与Collection 的add 方法非常不同。

    为什么不直接将 Set 接口定义为:

    public interface Set<E> extends Collection<E> {} 
    

    如果这样做了,就没有地方可以指定Set合约。我怎么知道通过实现Setadd 方法,我不应该允许重复?

    【讨论】:

    • 但是合同只是文件,对吧?所以从技术上讲,它不会有任何区别吗?只是其他开发者知道不同的意思吗?
    • 技术上,看成纯代码,完全没有区别。 只是其他开发人员知道不同的含义?:是的。这非常重要。
    • 好的,感谢您的澄清。问题仍然悬而未决:真正相同的功能,例如isEmptysize?为什么要重新声明?
    猜你喜欢
    • 1970-01-01
    • 2014-03-17
    • 2016-05-01
    • 2019-02-03
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 2018-01-23
    相关资源
    最近更新 更多