PriorityQueue 中的 CompareTo 和 equals
我对所有“如果 c 对 S 施加的排序与 equals 不一致,则排序集(或排序映射)将表现得很奇怪”感到有点困惑。 Javadoc 中的警告。 我什至不再确定 PriorityQueue 是我需要的......
我的情况是这样的: 我有一个带有整数时间戳和其他一些字段的类事件。 我正在寻找一种数据结构,我可以在其中插入这些事件并按时间戳对事件进行排序。 不同的事件可以具有相同的时间戳,因此 - 如果我理解正确 - CompareTo 和 equals 将不一致。
我的第一个方法是让 Event 实现 Comparable 并提供compareTo,如下所示: 公共 int 比较(事件 e){ 返回 this.timestamp - e.getTimestamp(); 我不明白
我应该如何解决这个问题。我考虑过创建一个自定义比较器,但是在比较器的 javadoc 中也弹出了关于奇怪行为的相同警告。 我不想插入事件的多个相等实例,我只想将它们按时间戳排序。
预先感谢您的帮助:)
编辑:
我只希望事件按时间戳排序。两个不同的事件很可能具有相同的时间戳。因此,compareTo 将返回 0,因为它们具有相同的时间戳并且对于排序而言是相等的。但 equals() 不会返回 true,因为它们是不同的事件。
我不确定,使用 PriorityQueue 是否正确。我查看了 SortedSet,但它对 CompareTo 和 equals 的一致性有相同的警告。
也许我从错误的角度来解决这个问题,我不知道......
i'm a little confused with all the "If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave strangely." warnings in the Javadoc.
I'm not even sure anymore a PriorityQueue is what i need...
My situation is this:
I have a class Event with an integer timestamp and some other fields.
I'm looking for a datastructure, in which I can insert these events and which sorts the events by timestamp.
Different events can have the same timestamp, so - if I understand correctly - compareTo and equals would be inconsistent.
My first approach was to let the Event implement Comparable and provide compareTo like this:
public int compareTo(Event e) {
return this.timestamp - e.getTimestamp();
}
I don't understand how I'm supposed to solve this. I thought about creating a custom Comparator, but the same warning about strange behaviour pops up in the Comparator's javadoc as well.
I don' want to insert multiple equal instances of an event, i just want them to be sorted by timestamp.
Thanks in advance for your help :)
Edit:
I just want the Events to be sorted by timestamp. It could very well be, that two different events have the same timestamp. So compareTo would return 0, because they have the same timestamp and are equal for the purpose of sorting. But equals() would not return true, because they are different events.
I'm not sure, a PriorityQueue is the right thing to use. I looked at SortedSet, but it had the same warnings about the consistency of compareTo and equals.
Maybe I'm tackling this from the wrong angle, I don't know...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
后一个要求有些不清楚。 Collection 的迭代器是否应该按排序顺序返回实例?或者,如果您在循环中
poll()
,集合是否应该按排序顺序返回其以前的内容?iterator()
按顺序返回元素PriorityQueue
的情况并非如此。您可以使用SortedSet
,但它们要求排序顺序与 equals 一致,正如您所注意到的,您无法实现这一点。据我所知,JDK 中没有Collection
可以将其元素保持在排序顺序中,以实现认为某些元素相等的排序顺序。但是,您可以使用数组或 ArrayList,并在更改后使用 Arrays.sort 或 Collection.sort 对其进行手动排序。如果集合很少变化,这就是我选择的方法。如果它经常更改,您将不得不超越 JDK 或自己实现数据结构。poll()
按排序顺序返回元素这就是优先级队列的优点。
PriorityQueue
不要求Comparator
(或Comparable
的实现)与 equals 一致;它的JavaDoc明确写道:而且,JDK 6中
PriorityQueue
的实现仅使用equals
来实现indexOf(E)
、contains(Object)
和remove(Object)
,两者都不以任何方式使用比较器。因此,对于这个Collection
来说,equals 的一致性实际上并不重要。Comparable 与 Comparator
请注意,就 equals 的一致性而言,实现 Comparable 还是 Comparator 并不重要。对于
SortedSet
,其中一个必须与 equals 一致,对于PriorityQueue
、Collection.sort
或Arrays.sort
,两者都不必是。TreeSet
以及与equals
的一致性摘自注释:
如果您报价,请报价所有相关部分。完整段落如下:
所以是的,它是明确定义的,但它并没有满足问题的要求:如果您传递
TreeSet.add
一个Event
,其时间戳与另一个>Event
在集合中,新的Event
将被视为重复且不会添加,即使Event
不相等
>。该问题询问如何对Collection
进行排序;这不应该消除重复排序键的事件
,不是吗?That latter requirement is somewhat unclear. Should the Collection's iterator return instances in sorted order? Or should the collection, if you
poll()
in a loop, return its former contents in sorted order?iterator()
returns elements in orderThat wouldn't be the case for a
PriorityQueue
. You could use aSortedSet
, but those require the sort order to be consistent with equals, which, as you note correctly, you can't achieve. As far as I know, there is noCollection
in the JDK that would keep its elements in sorted order for a sort order that considers some elements equal. However, you could use an array orArrayList
, and sort it manually after changes usingArrays.sort
orCollection.sort
. If the collection changes rarely, this is the approach I'd choose. If it changes frequently, you'll have to look beyond the JDK or implement the data structure yourself.poll()
returns elements in sorted orderThat's what a priority queue is good for. A
PriorityQueue
does not require theComparator
(or implementation ofComparable
) to be consistent with equals; its JavaDoc clearly writes:Moreover, the implementation of
PriorityQueue
in JDK 6 usesequals
only to implementindexOf(E)
,contains(Object)
andremove(Object)
, neither of which use the comparator in any way. So there really isn't a way consistency with equals could matter for thisCollection
.Comparable vs. Comparator
Note that it doesn't matter whether you implement Comparable or Comparator as far as consistency with equals is concerned. For a
SortedSet
, either must be consistent with equals, for aPriorityQueue
,Collection.sort
orArrays.sort
, neither has to be.TreeSet
and consistency withequals
Lifted from the comments:
If you quote, please quote all relevant parts. The full paragraph reads:
So yes it is well-defined, but it doesn't do what the question calls for: If you pass
TreeSet.add
anEvent
with the same timestamp as anotherEvent
in the set, the newEvent
will be considered a duplicate and not added, even though theEvent
s are notequal
. The question asks about sorting aCollection
; that should not eliminateEvents
that duplicate a sort key, should it?这仅仅意味着当且仅当
e1.equals(e2)
则e1.compareTo(e2) == 0
。当且仅当
!e1.equals(e2)
则e1.compareTo(e2) != 0
。这就是您必须做的才能使两种方法保持一致。
因此,通过实现compareTo的方式,您还应该重写equals()为:
注意:我不知道时间戳的数据类型,但如果它是原始类型,请使用
==
而不是equals()
用于重写方法。That just means that if and only if
e1.equals(e2)
thene1.compareTo(e2) == 0
.And if and only if
!e1.equals(e2)
thene1.compareTo(e2) != 0
.That is what you have to do to make both methods consistent.
So by the way you implement compareTo you should also override equals() as:
Note: I don't know timestamp's data type, but if it is a primitive type, use
==
instead ofequals()
for the overriden method.当您实现Comparable时,您还应该重写equals(Object),因为compareTo只应返回零当且仅当
equals< /code> 返回 true。
这还不是全部。由于另一个合同,当您覆盖
equals
时,您应该/必须覆盖hashCode()
。compareTo
、equals
和hashCode
实现取自您在java.lang.Long
中看到的实现。您还可以通过 Eclipse 等 IDE 生成这些方法。如果您希望在 equals 必须返回 false 时计算结果为 0(如另一条注释中所述),那么您必须实现 Comparator 而不是实现 Comparable。
When you implement
Comparable
then you should also overrideequals(Object)
, becausecompareTo
should only return zero if and only ifequals
return true.And that's not all. Due to another contract you should/must override
hashCode()
when you overrideequals
.compareTo
,equals
andhashCode
implementation was taken from the implementation you can see injava.lang.Long
. You can also generate these methods by an IDE like Eclipse.If you want to have a compareTo that evals to 0 when equals must return false (as stated in another comment), then you must implement a Comparator instead of implementing Comparable.