为什么java.util.Set <V>接口不提供get(Object o)方法?

Gre*_*nie 42 java generics collections

据我所知,在一个Set中只允许根据.equals()的任何对象的一个​​实例,如果你已经拥有一个等效的对象,你不应该"需要"从Set中获取一个对象,但我仍然希望有一个.get()方法,它给出一个等效对象作为参数的Set(或null)中对象的实际实例.

关于它为什么这样设计的任何想法/理论?

我通常不得不通过使用Map并使键和值相同或类似的东西来解决这个问题.

编辑:到目前为止,我认为人们不理解我的问题.我想要已经在集合中的确切对象实例,而不是可能不同的对象实例,其中.equals()返回true.

至于为什么我会想要这种行为,通常.equals()不会考虑对象的所有属性.我想提供一些虚拟查找对象并获取Set中的实际对象实例.

Dil*_*nga 30

虽然纯度论证确实使该方法get(Object)可疑,但潜在的意图并非没有实际意义.

有各种类和接口系列稍微重新定义equals(Object).只需要集合界面就可以了.例如,ArrayList和LinkedList可以相等; 它们各自的内容只需要是相同的并且顺序相同.

因此,找到集合中的匹配元素有很好的理由.也许更明确的表达意图的方法是使用类似的方法

public interface Collection<E> extends ... {
  ...
  public E findMatch(Object o) throws UnsupportedOperationException;
  ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,此API的值大于Set中的值.

至于问题本身,我没有任何关于为什么省略这种操作的理论.我会说最小生成集参数不成立,因为集合API中定义的许多操作都是出于方便和高效的原因.

  • 因此,总而言之,我们没有充分的理由不拥有具有此类功能的集合. (5认同)
  • 许多"为什么XX不做YY"问题的答案是"因为有人认为不应该".实际上,这几乎是所有这些问题的真正答案.一个更好的问题可能是"有没有人设计XX不应该让它做YY".我喜欢你发现隐含的问题并回答"在这种情况下,有人设计XX应该做YY的原因,即使Java的XX没有这样做". (4认同)

GCl*_*unt 12

问题是:Set不是用于"获取"对象,而是用于添加和测试存在.我理解你在寻找什么,我有类似的情况,最后使用键和值中相同对象的地图.

编辑:只是为了澄清:http://en.wikipedia.org/wiki/Set_(abstract_data_type)


小智 6

几年前我在java论坛上遇到了同样的问题.他们告诉我定义了Set接口.它无法更改,因为它将破坏Set接口的当前实现.然后,他们开始要求废话,就像你在这里看到:"集不需要get方法",并开始钻我,地图必须始终用来从一组元素.

如果你只使用set进行数学运算,比如intersection或union,那么可能是contains()就足够了.但是,Set在集合中定义以存储数据.我在Set中使用关系数据模型解释了需要get().

在下文中,SQL表就像一个类.列定义属性(在Java中称为字段),记录表示类的实例.这样一个对象就是一个字段向量.一些字段是主键.它们定义了对象的唯一性.这就是你在Java中为contains()做的事情:

class Element {

        public int hashCode() {return sumOfKeyFields()}
        public boolean equals(Object e) {keyField1.equals(e) && keyField2.equals(e) && ..}
Run Code Online (Sandbox Code Playgroud)

我不知道DB内部.但是,在定义表时,只指定一次键字段.您只需使用@primary注释关键字段.在向表中添加记录时,不会第二次指定键.您不像在映射中那样将键与数据分开.SQL表是集合.它们不是地图.然而,除了保持唯一性和contains()检查之外,它们还提供了get().

在"计算机编程艺术"中,介绍搜索,D.Knuth说:

本章的大部分内容都致力于研究一个非常简单的搜索问题:如何查找已使用给定标识存储的数据.

你看,数据存储有标识.没有标识指向的数据,但与识别数据.他继续:

例如,在数值应用中,我们可能想要找到f(x),给定x和f值的表格; 在非数字应用程序中,我们可能希望找到给定俄语单词的英语翻译.

看起来他开始谈论绘图.然而,

一般来说,我们假设已经存储了一组N条记录,问题是找到合适的记录.我们通常要求N键是不同的,以便每个键唯一地标识其记录.所有记录的集合称为文件,这里所说的"表",通常用来表示一个小文件,"文件"通常用来表示一个大表.大文件或一组文件通常称为数据库.

用于搜索的算法用所谓的参数K表示,问题是找到哪个记录以K为其键.虽然搜索的目的是找到存储在与K相关联的记录中的信息,但本章中的算法通常会忽略除键本身之外的所有内容.在实践中,一旦找到K,我们就可以找到相关数据; 例如,如果K出现在位置TABLE + i中,则关联数据(或指向它的指针)可能位于位置TABLE + i + 1

也就是说,搜索找到记录的密钥字段,它不应该将密钥"映射"到数据.两者都位于相同的记录中,作为java对象的文件.也就是说,搜索算法检查记录的关键字段,就像在集合中一样,而不是像地图中那样检查某些远程密钥.

我们有N个要分类的项目; 我们将它们称为记录,并将整个N条记录集合称为文件.每个记录Rj都有一个密钥Kj,它控制着分类过程.除钥匙外,其他数据通常也存在; 这种额外的"卫星信息"对分类没有影响,只是它必须作为每个记录的一部分携带.

在我的排序讨论中,我认为没有必要在额外的"密钥集"中复制密钥.

...... ["计算机程序设计的艺术",第6章,导言]

实体集是集合或设置特定实体类型的所有实体[http://wiki.answers.com/Q/What_is_entity_and_entity_set_in_dbms]单个类的对象共享其类属性.同样,在DB中做记录.它们共享列属性.

集合的一个特例是类范围,它是属于该类的所有对象的集合.类扩展区允许将类视为关系

...... ["数据库系统概念",第6版]

基本上,class描述了其所有实例共有的属性.关系数据库中的表也是如此."您将拥有的最简单的映射是将单个属性映射到单个列." 这就是我所说的情况.

我在证明对象和DB记录之间的类比(同构)方面非常冗长,因为有些愚蠢的人不接受它(为了证明他们的Set不能有get方法)

你在回放中看到了那些不理解这一点的人,怎么说Set with get会多余?这是因为他们用来代替集合的滥用地图引入了冗余.他们呼吁把(obj.getKey(),OBJ)存储两个密钥:原来的键作为对象的一部分,它在地图上的按键副本.重复是冗余.它还涉及代码中的更多膨胀并浪费运行时消耗的内存.我不知道数据库内部,但良好设计和数据库规范化的原则说这种重复是个坏主意 - 必须只有一个事实来源.冗余意味着可能发生不一致:键映射到具有不同键的对象.不一致是冗余的表现.Edgar F. Codd提出数据库规范化只是为了摆脱冗余及其推断的不一致性.教师明确规范化:规范化永远不会生成两个表,它们之间具有一对一的关系.没有理论上的理由将这样的单个实体与一个表的单个记录中的某些字段分开,而将另一个表的单个记录中的其他字段分开

所以,我们有4个参数,为什么使用map实现get in set很糟糕:

  1. 当我们有一组唯一对象时,地图是不必要的
  2. map在运行时存储中引入冗余
  3. map在DB中引入代码膨胀(在集合中)
  4. 使用map与数据存储规范化相矛盾

即使您不了解记录集构思和数据规范化,使用集合,您也可以自己发现这种数据结构和算法,就像我们org.eclipse.KeyedHashSet和C++ STL设计者所做的那样.

我在Sun论坛上被禁止指出这些想法.偏见是反对这个理由的唯一论据,这个世界由偏执者主宰.他们不希望看到概念以及事物如何不同/改进.他们只看到现实世界,无法想象Java Collections的设计可能存在缺陷并且可以改进.向这些人提醒理性事物是危险的.如果你不服从,他们会教导你他们的失明和惩罚.

2013年12月新增:SICP还说数据库是一个包含键控记录而不是地图的集合:

典型的数据管理系统花费大量时间来访问或修改记录中的数据,因此需要一种有效的方法来访问记录.这是通过识别每个记录的一部分来充当识别密钥来完成的.现在我们将数据库表示为一组记录.