Treeset.contains()问题 [英] Treeset.contains() problem
问题描述
所以我现在一直在努力解决问题,我想在这里也可以寻求帮助。
So I've been struggling with a problem for a while now, figured I might as well ask for help here.
我将Ticket对象添加到一个TreeSet,Ticket实现了Comparable并重写了equals(),hashCode()和CompareTo()方法。我需要使用contains()检查对象是否已经在TreeSet中。现在在向集合中添加2个元素后,它们都检查得很好,但是在添加第三个元素之后它就搞砸了。
I'm adding Ticket objects to a TreeSet, Ticket implements Comparable and has overridden equals(), hashCode() and CompareTo() methods. I need to check if an object is already in the TreeSet using contains(). Now after adding 2 elements to the set it all checks out fine, yet after adding a third it gets messed up.
在添加第三个元素之后运行这一小段代码对于TreeSet,Ticket temp2是我正在检查的对象(verkoopLijst)。
running this little piece of code after adding a third element to the TreeSet, Ticket temp2 is the object I'm checking for(verkoopLijst).
Ticket temp2 = new Ticket(boeking, TicketType.STANDAARD, 1,1);
System.out.println(verkoop.getVerkoopLijst().first().hashCode());
System.out.println(temp2.hashCode());
System.out.println(verkoop.getVerkoopLijst().first().equals(temp2));
System.out.println(verkoop.getVerkoopLijst().first().compareTo(temp2));
System.out.println(verkoop.getVerkoopLijst().contains(temp2));
返回:
22106622
22106622
true
0
false
现在我的问题是如何做到这一点?
Now my question would be how this is even possible?
编辑:
public class Ticket implements Comparable{
private int rijNr, stoelNr;
private TicketType ticketType;
private Boeking boeking;
public Ticket(Boeking boeking, TicketType ticketType, int rijNr, int stoelNr){
//setters
}
@Override
public int hashCode(){
return boeking.getBoekingDatum().hashCode();
}
@Override
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object o){
Ticket t = (Ticket) o;
if(this.boeking.equals(t.getBoeking())
&&
this.rijNr == t.getRijNr() && this.stoelNr == t.getStoelNr()
&&
this.ticketType.equals(t.getTicketType()))
{
return true;
}
else return false;
}
/*I adjusted compareTo this way because I need to make sure there are no duplicate Tickets in my treeset. Treeset seems to call CompareTo() to check for equality before adding an object to the set, instead of equals().
*/
@Override
public int compareTo(Object o) {
int output = 0;
if (boeking.compareTo(((Ticket) o).getBoeking())==0)
{
if(this.equals(o))
{
return output;
}
else return 1;
}
else output = boeking.compareTo(((Ticket) o).getBoeking());
return output;
}
//Getters & Setters
推荐答案
On compareTo
合约
问题在于你的 compareTo
。以下是文档的摘录:
On compareTo
contract
The problem is in your compareTo
. Here's an excerpt from the documentation:
实施者必须确保
sgn(x.compareTo(y))== -sgn(y.compareTo(x) )
所有x
和y
。
您的原始代码转载于此处供参考:
Your original code is reproduced here for reference:
// original compareTo implementation with bug marked
@Override
public int compareTo(Object o) {
int output = 0;
if (boeking.compareTo(((Ticket) o).getBoeking())==0)
{
if(this.equals(o))
{
return output;
}
else return 1; // BUG!!!! See explanation below!
}
else output = boeking.compareTo(((Ticket) o).getBoeking());
return output;
}
为什么返回1;
一个错误?请考虑以下情形:
Why is the return 1;
a bug? Consider the following scenario:
- 给定
票证t1,t2
- 给定
t1.boeking.compareTo(t2.boeking)== 0
- 给定
t1.equals(t2)
returnfalse
- 现在我们有以下两种情况:
-
t1.compareTo(t2)
返回1
-
t2.compareTo(t1)
返回1
- Given
Ticket t1, t2
- Given
t1.boeking.compareTo(t2.boeking) == 0
- Given
t1.equals(t2)
returnfalse
- Now we have both of the following:
t1.compareTo(t2)
returns1
t2.compareTo(t1)
returns1
最后一个结果是 违规
compareTo
合约。That last consequence is a violation of the
compareTo
contract.首先,您应该利用
Comparable< T>
是可参数化的泛型类型的事实。也就是说,而不是:First and foremost, you should have taken advantage of the fact that
Comparable<T>
is a parameterizable generic type. That is, instead of:// original declaration; uses raw type! public class Ticket implements Comparable
更适合宣布像这个:
// improved declaration! uses parameterized Comparable<T> public class Ticket implements Comparable<Ticket>
现在我们可以编写
compareTo(Ticket)
(不再compareTo(Object)
)。有很多方法可以重写这个,但这里有一个相当简单的方法:Now we can write our
compareTo(Ticket)
(no longercompareTo(Object)
). There are many ways to rewrite this, but here's a rather simplistic one that works:@Override public int compareTo(Ticket t) { int v; v = this.boeking.compareTo(t.boeking); if (v != 0) return v; v = compareInt(this.rijNr, t.rijNr); if (v != 0) return v; v = compareInt(this.stoelNr, t.stoelNr); if (v != 0) return v; v = compareInt(this.ticketType, t.ticketType); if (v != 0) return v; return 0; } private static int compareInt(int i1, int i2) { if (i1 < i2) { return -1; } else if (i1 > i2) { return +1; } else { return 0; } }
现在我们还可以定义
等于(对象)
就compareTo(Ticket)
而不是相反:Now we can also define
equals(Object)
in terms ofcompareTo(Ticket)
instead of the other way around:@Override public boolean equals(Object o) { return (o instanceof Ticket) && (this.compareTo((Ticket) o) == 0); }
注意
compareTo $ c的结构$ c>:它有多个
return
语句,但事实上,逻辑流程非常易读。另请注意排序标准的优先级是如何明确的,并且如果您有不同的优先级,则可以轻松重新排序。Note the structure of the
compareTo
: it has multiplereturn
statements, but in fact, the flow of logic is quite readable. Note also how the priority of the sorting criteria is explicit, and easily reorderable should you have different priorities in mind.- What is a raw type and why shouldn't we use it?
- How to sort an array or ArrayList ASC first by x and then by y?
- Should a function have only one return statement?
这篇关于Treeset.contains()问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
-