Java:如何解决缺少 Equatable 接口的问题?
据我所知,诸如 SortedMap
或 SortedSet
之类的东西,在 compareTo
(而不是 equals
)上使用 <用于检查相等性的 code>Comparable 类型(contains
、containsKey
)。
但是,如果某些类型在概念上是等同的,但不具有可比性怎么办?
(哈希码、内存地址...)
我必须声明一个 Comparator
并重写方法 int CompareTo(T o1, To2)
。好的,对于被认为相等的实例,我可以返回 0。但是,对于特殊情况,当订单不明显时我应该返回什么?
在 equatable 但(根据概念)不可比较类型上使用 SortedMap 或 SortedSet 的方法是否良好?
谢谢你!
编辑:
我不想存储已排序的内容,但是如果我使用“通常的”映射和集合,我无法“覆盖”平等行为。
编辑2:
为什么我不能直接重写 equals(...)
:
我需要改变外国阶层的平等行为。我无法编辑它。
编辑 3:
想想 .NET:它们有 IEquatable 接口,可以改变相等行为而不触及可比行为。
编辑4:
我不能让 compareTo
返回 0(表示相等)和 1(表示不相等)吗?有什么大问题?我已经进行了一些测试,似乎 SortedMap/SortedSet 在一对实例上调用了一次compareTo。是的,这个顺序没有意义,但为什么这是我的问题呢?我不需要订单。 *我只需要改变平等行为。可悲的是大多数人无法理解这一点。
注意:对于不相等的实例返回 1 的概念现在已被证明是错误的。
编辑5:
改变外国阶层的平等行为是一个坏主意吗?当然?我不这么认为:为什么我可以使用 Comparator
改变外部类的比较行为?
编辑6:
感谢 Mark Peters
和 waxwing
将密钥类型包装在自定义类中的想法。这样,我可以覆盖 equals 和 hashCode,从而改变相等行为。
As far as I know, things such as SortedMap
or SortedSet
, use compareTo
(rather than equals
) on Comparable<?>
types for checking equality (contains
, containsKey
).
But what if certain types are equatable by concept, but not comparable?
(Hash codes, memory addresses, ...)
I have to declare a Comparator<?>
and override the method int compareTo(T o1, To2)
. OK, I can return 0 for instances which are considered equal. But, for unqeual instances, what do I return when an order is not evident?
Is the approach of using SortedMap or SortedSet on equatable but (by concept) not comparable types good anyway?
Thank you!
EDIT:
I don't want to store things sorted, but would I use "usual" Map and Set, I couldn't "override" the equality-behavior.
EDIT 2:
Why I can't just override equals(...)
:
I need to alter the equality-behavior of a foreign class. I can't edit it.
EDIT 3:
Just think of .NET: They have IEquatable interface which cat alter the equality-behavior without touching the comparable behavior.
EDIT 4:
Can't I just make compareTo
return 0 for equal and 1 for non-equal instances? What's the big problem? I've dome some tests, it seems that SortedMap/SortedSet call compareTo on a pair of instances once. Yes, the order would not make sense, but why should it be my problem? I don't need the order. *I just need altered equality-behavior. Sadly most people just can't understand this.
NOTE: The concept of returning 1 for non-equal instances now was proven wrong.
EDIT 5:
Altering equality-behavior of foreign classes is a bad concept? Sure? I don't think so: Why then am I allowed to alter comparison-behavior of foreign classes using Comparator
?
EDIT 6:
Thanks to Mark Peters
and waxwing
for the idea of wrapping the key type in a custom class. This way, I can override equals and hashCode, thus altering the equality-behavior.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
考虑将您的外国课程包装在您自己的课程中。
然后
将
newforeignWrapper(foreign)
添加到标准HashSet/HashMap中。并不适用于所有情况,但也许适用于您的情况。Consider wrapping your foreign class inside your own instead.
}
Then add
new ForeignWrapper(foreign)
to the standard HashSet / HashMap. Not applicable in all situations, but maybe in yours.不,在可等同但不可比较的类型上使用 SortedMap 或 SortedSet 是一个可怕的想法。如果它们本质上或通过比较器不具有可比性,则不应在 SortedSet 中使用它们。排序意味着有顺序,这意味着您可以比较两个项目以查看哪个项目“较少”。
只需使用 HashMap/Set 即可。
编辑你的编辑 #2
如果你不能正确地覆盖 equals,那么你的设计就很糟糕了。您需要提供更多有关您想要完成的任务的信息。
编辑您的编辑 #3
在 Java 中,修改 equals 不会改变类似的行为。您不需要界面来完成此任务。
编辑到您的编辑 #4
不,您不能只为不相等的元素返回 1!!
SortedSet 使用比较来找到您的元素该集。类似的接口有特定的要求。您要破坏的一个是 if
A.compareTo(B) > 0
,则必然B.compareTo(A) < 0 。您正在破坏这将导致无法在您的后记中找到元素。
此代码打印
false
,因此显然您的比较器破坏了 Set 的语义。No, using SortedMap or SortedSet on equatable but not comparable types is a horrible idea. If they're not comparable intrisically or through a comparator, they should not be used in a SortedSet. Sorted implies there is ordering, meaning you can compare two items to see which is "less".
Just use a HashMap/Set.
Edit to your Edit #2
If you can't properly override equals, somewhere you've got a very bad design. You would need to give more info into what you're trying to accomplish.
Edit to your Edit #3
In Java, modifying equals does not change the comparable behaviour. You don't need an interface to accomplish that.
Edit to your Edit #4
NO, YOU CANNOT JUST RETURN 1 FOR NON-EQUAL ELEMENTS!!
SortedSets use the comparison to find your element in the set. The comparable interface has specific requirements. The one that you're breaking is that if
A.compareTo(B) > 0
, then necessarilyB.compareTo(A) < 0
. You're breaking that which would make it impossible to find elements in your set afterwords.This code prints
false
, so obviously your comparator has broken the semantics of a Set.看起来您不想/不需要对元素进行排序。
在这种情况下,也许您可以使用
HashMap
和HashSet
来代替?如果不需要排序,则使用SortedMap
和SortedSet
是没有意义的。It looks like you don't want/need to sort the elements.
In that case, maybe you can use
HashMap
andHashSet
instead? There is no point of usingSortedMap
andSortedSet
if you don't need it to be sorted.如果您不想存储已排序的元素,那么为什么要使用已排序的集合呢?
为了维护排序的集合,插入操作(通常)具有 O(log n) 复杂度来将元素放置在正确的位置。如果您不需要排序,那么这是浪费的,因为您可能使用基于哈希的集合(HashMap、HashSet),这会给您带来 O(1) 的插入时间。
If you don't want to store your elements sorted, then why are you using a sorted collection?
In order to maintain a sorted collection, an insert operation (typically) has O(log n) complexity to place the element in the correct place. If you don't need sorting, then this is wasteful, as you could be using a hash-based collection (HashMap, HashSet) which would give you O(1) insertion time.
不。这些集合的目的是允许您对其中的对象进行排序,如果对象没有自然的排序顺序,那么将它们放入已排序的集合中有何意义?
您应该重写 equals() 和 hashcode() 方法并使用标准 Map/Set 类。
No. The point of these collections is to allow you to sort the objects in them, if the objects don't have a natural sorting order then what is the point of putting them in a sorted collection?
You should override the equals() and hashcode() methods and use the standard Map/Set classes instead.
如果您需要重写 hashCode 但不能,我认为您正在考虑扩展 HashMap 或编写自己的 HashMap。
If you need to override hashCode but can't, I think you're looking at extending HashMap or writing your own.
目前尚不清楚,但可能您想要做的就是获取一个 somethings 的集合,使用与 Set/Map 相同的语义,但使用 somethings没有充分实现
Object.equals
。在这种情况下,我建议您继承
AbstractSet
或AbstractMap
并重写AbstractCollection.contains
以使用您的 equals 版本。这不是我推荐的,但你的问题实际上并没有明确你想要实现的目标。
请参阅 http://java.sun.com/javase /6/docs/api/java/util/AbstractSet.html
和 http: //java.sun.com/javase/6/docs/api/java/util/AbstractCollection.html#contains(java.lang.Object)
It's not clear, but it could be that all you're trying to do is get a Collection of somethings, using the same semantics of Set/Map, but with somethings that don't adequately implement
Object.equals
.In that case I suggest you subclass
AbstractSet
orAbstractMap
and overrideAbstractCollection.contains
to use your version of equals.It's not something I'd recommend, but your question doesn't actually make it clear what you're trying to achieve.
See http://java.sun.com/javase/6/docs/api/java/util/AbstractSet.html
and http://java.sun.com/javase/6/docs/api/java/util/AbstractCollection.html#contains(java.lang.Object)
如果内存不是大问题,则子类 HashMap 和 HashSet 采取 Equality 类,
这样您就可以定义自己的相等行为。奇怪的是jre中缺少它
If memory is not a big problem subclass HashMap and HashSet to take an Equality class
This way you can define your own equality behavior. Strange that it is missing from the jre
如果对象不具有可比性,则无法对其进行排序;如果两个对象不具有可比性,您如何知道哪一个应该排在第一位?因此,无法将不具有可比性的对象放入
SortedMap
或SortedSet
中。 (为什么要这样做?使用不同类型的Map
或Set
)。Java 中的
equals()
方法在类Object
中定义,并且由于所有类都扩展Object
,因此所有对象都有一个equals( )
方法。如果您希望能够判断两个对象是否相等,则必须注意在类中正确重写和实现 equals() 。如果要将对象放入基于哈希的集合(例如
HashMap
或HashSet
)中,您还必须重写hashCode()
并且必须确保以正确的方式实现hashCode()
和equals()
(有关如何实现的详细信息,请参阅类Object
中这些方法的文档)来做到这一点)。You cannot sort objects if they are not comparable; how would you know which of the two objects should come first if they are not comparable? So there is no way to put objects that are not comparable in a
SortedMap
orSortedSet
. (Why would you want to? Use a different kind ofMap
orSet
).The
equals()
method in Java is defined in classObject
, and since all classes extendObject
, all objects have anequals()
method. You have to take care that you override and implementequals()
correctly in your classes if you want to be able to tell if two objects are equal.If you want to put objects in a hash-based collection (such as
HashMap
orHashSet
) you must also overridehashCode()
and you must make sure thathashCode()
andequals()
are implemented the right way (see the documentation of those methods in classObject
for details on how to do that).正如其他人所说,如果没有自然顺序,SortedXXX 并不是真正的选择。
但是,假设您只是想要某种一致的方式列出元素,如果您只考虑用于相等性测试的字段,因为这些字段构成“主键”,并提出某种数字或字母顺序围绕它们可能适合您的目的。
As others have said, if there is no natural order a SortedXXX isn't really an option.
However, assuming you just want some kind of consistent way of listing the elements, if you just consider the fields that you are using for equality testing, as these constitute the "primary key", and come up with some sort of numerical or alphabetical ordering around them that might suit your purpose.
只需在创建 Sorted[Set|Map] 时使用为实现 Sorted[Set|Map] 提供的(自定义)比较器...
javadocs 往往会建议这样做:
插入排序映射中的所有键都必须实现 Comparable 接口(或被指定的比较器接受)。
http://java.sun .com/javase/6/docs/api/
Just use a (custom) Comparator provided to the implementation of Sorted[Set|Map] when you create it...
The javadocs would tend to suggest this:
All keys inserted into a sorted map must implement the Comparable interface (or be accepted by the specified comparator).
http://java.sun.com/javase/6/docs/api/
我不确定我是否明白你的观点(我认为你试图从错误的方向解决问题),但如果你毕竟只是想要一个
Set
或Map 维护插入顺序,然后使用
LinkedHashSet
或LinkedHashMap
。更新:根据您的报价:
在排序集/地图内?然后使用
TreeSet
或TreeMap
,您使用自定义比较器
。例如(它构造了一组按不区分大小写的顺序排序的
String
)。另请参阅:
I am not sure if I see your point (I think you're trying to solve a problem from the wrong direction on), but if you after all just want a
Set
orMap
which maintains insertion order, then useLinkedHashSet
orLinkedHashMap
respectively.Update: as per your quote:
Inside a sorted set/map? Then use a
TreeSet
orTreeMap
which you construct with a customComparator
. E.g.(which constructs a set of
String
s ordered in case insensitive order).See also:
您正在尝试重写未知类型的 equals() 方法。您正在考虑希望拥有 IEquatable 接口的问题。如果必须使用 SortedSet/SortedMap,则提供一个比较器,例如 @ptomli 在他的回答中提到。
使用 HashMap/HashSet 似乎是一个不错的建议。你看过那些吗?
You are trying to override the equals() method of an unknown type. You are thinking about the problem wishing you had the IEquatable interface. If you must use SortedSet/SortedMap then provide a Comparator like @ptomli mentions in his answer.
Using HashMap/HashSet instead seems to be a good suggestion. Have you looked at those?