为什么 java.util.Set<V> 接口不提供 get(Object o) 方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/861296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does the java.util.Set<V> interface not provide a get(Object o) method?
提问by GreenieMeanie
I understand that only one instance of any object according to .equals() is allowed in a Set and that you shouldn't "need to" get an object from the Set if you already have an equivalent object, but I would still like to have a .get() method that returns the actual instance of the object in the Set (or null) given an equivalent object as a parameter.
我知道在 Set 中只允许根据 .equals() 的任何对象的一个实例,如果你已经有一个等效的对象,你不应该“需要”从 Set 中获取一个对象,但我仍然想有一个 .get() 方法,它返回 Set 中对象的实际实例(或 null),给定一个等效对象作为参数。
Any ideas/theories as to why it was designed like this?
关于为什么这样设计的任何想法/理论?
I usually have to hack around this by using a Map and making the key and the value same, or something like that.
我通常必须通过使用 Map 并使键和值相同或类似的东西来解决这个问题。
EDIT: I don't think people understand my question so far. I want the exact object instance that is already in the set, not a possibly different object instance where .equals() returns true.
编辑:我认为到目前为止人们还没有理解我的问题。我想要集合中已经存在的确切对象实例,而不是 .equals() 返回 true 的可能不同的对象实例。
As to why I would want this behavior, typically .equals() does not take into account all the properties of the object. I want to provide some dummy lookup object and get back the actual object instance in the Set.
至于为什么我想要这种行为,通常 .equals() 不会考虑对象的所有属性。我想提供一些虚拟查找对象并取回 Set 中的实际对象实例。
采纳答案by Dilum Ranatunga
While the purity argument does make the method get(Object)
suspect, the underlying intent is not moot.
虽然纯度论点确实使该方法受到get(Object)
怀疑,但潜在的意图并没有实际意义。
There are various class and interface families that slightly redefine equals(Object)
. One need look no further than the collections interfaces. For example, an ArrayList and a LinkedList can be equal; their respective contents merely need to be the same and in the same order.
有各种稍微重新定义的类和接口系列equals(Object)
。只需查看集合接口即可。例如,ArrayList 和 LinkedList 可以相等;它们各自的内容只需相同且顺序相同即可。
Consequently, there are very good reasons for finding the matchingelement in a set. Perhaps a clearer way of indicating intent is to have a method like
因此,在集合中找到匹配元素有很好的理由。也许一种更清晰的表示意图的方法是使用类似的方法
public interface Collection<E> extends ... {
...
public E findMatch(Object o) throws UnsupportedOperationException;
...
}
Note that this API has value broader that within Set.
请注意,此 API 的值比 Set 中的值更广泛。
As to the question itself, I don't have any theory as to why such an operation was omitted. I will say that the minimal spanning set argumentdoes not hold, because many operations defined in the collections APIs are motivated by convenience and efficiency.
至于问题本身,我没有任何关于为什么省略这样一个操作的理论。我会说最小生成集参数不成立,因为集合 API 中定义的许多操作都是为了方便和效率。
回答by andersoj
Well, if you've already "got" the thing from the set, you don't need to get() it, do you? ;-)
好吧,如果你已经从集合中“得到”了那个东西,你就不需要 get() 了,是吗?;-)
Your approach of using a Map is The Right Thing, I think. It sounds like you're trying to "canonicalize" objects via their equals() method, which I've always accomplished using a Map as you suggest.
我认为您使用地图的方法是正确的。听起来您正在尝试通过它们的 equals() 方法“规范化”对象,我一直按照您的建议使用 Map 来完成该方法。
回答by alphazero
I think you've answered your own question: it is redundant.
我想你已经回答了你自己的问题:这是多余的。
Set provides Set#contains (Object o) which provides the equivalent identity test of your desired Set#get(Object o) and returns a boolean, as would be expected.
Set 提供了 Set#contains (Object o),它提供了您想要的 Set#get(Object o) 的等效身份测试并返回一个布尔值,正如预期的那样。
回答by GClaramunt
The problem is: Set is not for "getting" objects, is for adding and test for presence. I understand what are you looking for, I had a similar situation and ended using a map of the same object in key and value.
问题是:Set 不是用于“获取”对象,而是用于添加和测试是否存在。我了解您在寻找什么,我遇到了类似的情况,并最终在键和值中使用了相同对象的映射。
EDIT: Just to clarify: http://en.wikipedia.org/wiki/Set_(abstract_data_type)
编辑:只是为了澄清:http: //en.wikipedia.org/wiki/Set_(abstract_data_type)
回答by Matthew Flaschen
"I want the exact object instance that is already in the set, not a possibly different object instance where .equals() returns true."
“我想要集合中已经存在的确切对象实例,而不是 .equals() 返回 true 的可能不同的对象实例。”
This doesn't make sense. Say you do:
这没有意义。说你这样做:
Set<Foo> s = new Set<Foo>();
s.Add(new Foo(...));
...
Foo newFoo = ...;
You now do:
你现在做:
s.contains(newFoo)
If you want that to only be true if an object in the set is == newFoo, implement Foo's equals and hashCode with object identity. Or, if you're trying to map multiple equal objects to a canonical original, then a Map may be the right choice.
如果您希望仅当集合中的对象是 == newFoo 时才为真,请使用对象标识实现 Foo 的 equals 和 hashCode。或者,如果您尝试将多个相等的对象映射到规范的原始对象,那么 Map 可能是正确的选择。
回答by Yishai
I think the expectation is that equals truely represent some equality, not simply that the two objects have the same primary key, for example. And if equals represented two really equal objects, then a get would be redundant. The use case you want suggests a Map, and perhaps a different value for the key, something that represents a primary key, rather than the whole object, and then properly implement equals and hashcode accordingly.
我认为期望是 equals 真正代表某种相等性,而不仅仅是两个对象具有相同的主键,例如。如果 equals 代表两个真正相等的对象,那么 get 将是多余的。您想要的用例建议一个 Map,可能还有一个不同的键值,它代表一个主键,而不是整个对象,然后相应地正确实现 equals 和 hashcode。
回答by Oren Shalev
I'm not sure if you're looking for an explanation of why Sets behave this way, or for a simple solution to the problem it poses. Other answers dealt with the former, so here's a suggestion for the latter.
我不确定您是在寻找对 Set 为何如此表现的解释,还是在寻找解决它所带来问题的简单解决方案。其他答案涉及前者,所以这是对后者的建议。
You can iterate over the Set's elements and test each one of them for equality using the equals() method. It's easy to implement and hardly error-prone. Obviously if you're not sure if the element is in the set or not, check with the contains() method beforehand.
您可以迭代 Set 的元素并使用 equals() 方法测试它们中的每一个元素是否相等。它易于实施且不易出错。显然,如果您不确定该元素是否在集合中,请事先检查 contains() 方法。
This isn't efficient compared to, for example, HashSet's contains() method, which does "find" the stored element, but won't return it. If your sets may contain many elements it might even be a reason to use a "heavier" workaround like the map implementation you mentioned. However, if it's that important for you (and I do see the benefit of having this ability), it's probably worth it.
例如,与 HashSet 的 contains() 方法相比,这并不高效,该方法确实“查找”了存储的元素,但不会返回它。如果您的集合可能包含许多元素,则甚至可能是使用“更重”的解决方法(例如您提到的地图实现)的原因。但是,如果它对您很重要(而且我确实看到了拥有此功能的好处),那么它可能是值得的。
回答by Apocalisp
Functional Javahas an implementation of a persistent Set (backed by a red/black tree) that incidentally includes a splitmethod that seems to do kind of what you want. It returns a triplet of:
函数式 Java有一个持久集的实现(由红/黑树支持),顺便说一下,它包含一个split方法,它似乎可以做你想做的事情。它返回一个三元组:
- The set of all elements that appear before the found object.
- An object of type
Option
that is either empty or contains the found object if it exists in the set. - The set of all elements that appear after the found object.
- 出现在找到的对象之前的所有元素的集合。
- 类型
Option
为空或包含找到的对象(如果它存在于集合中)的对象。 - 在找到的对象之后出现的所有元素的集合。
You would do something like this:
你会做这样的事情:
MyElementType found = hayStack.split(needle)._2().orSome(hay);
回答by Sorin Mocanu
So I understand that you may have two equal objects but they are not the same instance.
所以我知道您可能有两个相同的对象,但它们不是同一个实例。
Such as
如
Integer a = new Integer(3);
Integer b = new Integer(3);
In which case a.equals(b) because they refer to the same intrinsic value but a != b because they are two different objects.
在这种情况下 a.equals(b) 因为它们引用相同的内在值但 a != b 因为它们是两个不同的对象。
There are other implementations of Set, such as IdentitySet, which do a different comparison between items.
Set 还有其他实现,例如IdentitySet,它们在项目之间进行不同的比较。
However, I think that you are trying to apply a different philosophy to Java. If your objects are equal (a.equals(b)) although a and b have a different state or meaning, there is something wrong here. You may want to split that class into two or more semantic classes which implement a common interface - or maybe reconsider .equals and .hashCode.
但是,我认为您正在尝试将不同的哲学应用于 Java。如果您的对象相等 (a.equals(b)) 尽管 a 和 b 具有不同的状态或含义,那么这里就有问题了。您可能希望将该类拆分为两个或多个实现公共接口的语义类 - 或者重新考虑 .equals 和 .hashCode。
If you have Joshua Bloch's Effective Java, have a look at the chapters called "Obey the general contract when overriding equals" and "Minimize mutability".
如果您有 Joshua Bloch 的Effective Java,请查看名为“Obey the general contract when overriding equals”和“Minimize mutability”的章节。
回答by user85421
Just use the Map solution... a TreeSet and a HashSet also do it since they are backed up by a TreeMap and a HashMap, so there is no penalty in doing so (actualy it should be a minimal gain).
只需使用 Map 解决方案... TreeSet 和 HashSet 也可以这样做,因为它们由 TreeMap 和 HashMap 支持,因此这样做没有任何损失(实际上它应该是最小的收益)。
You may also extend your favorite Set to add the get() method.
您还可以扩展您最喜欢的 Set 以添加 get() 方法。
[]]
[]]