所以我现在一直在努力解决问题,我想在这里也可以寻求帮助。
我将Ticket对象添加到TreeSet,Ticket实现Comparable并重写了equals(),hashCode()和CompareTo()方法。我需要使用contains()检查对象是否已经在TreeSet中。现在在将2个元素添加到集合之后,它们都检查得很好,但是在添加第三个元素之后它会搞砸了。
在向TreeSet添加第三个元素后运行这一小段代码,Ticket temp2是我正在检查的对象(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
现在我的问题是如何做到这一点?
编辑:
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
答案 0 :(得分:18)
compareTo
合同问题出在compareTo
。以下摘自the documentation:
执行者必须确保所有
sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
和x
都y
。
您的原始代码转载于此处以供参考:
// 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;
}
为什么return 1;
是个错误?请考虑以下情形:
Ticket t1, t2
t1.boeking.compareTo(t2.boeking) == 0
t1.equals(t2)
返回false
t1.compareTo(t2)
返回1
t2.compareTo(t1)
返回1
最后一个结果是compareTo
合同的 违规行为 。
首先,您应该利用Comparable<T>
是可参数化的泛型类型的事实。也就是说,而不是:
// 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)
)。有很多方法可以重写这个,但这里有一个相当简单的方法:
@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;
}
}
现在我们也可以用equals(Object)
而不是相反的方式定义compareTo(Ticket)
:
@Override public boolean equals(Object o) {
return (o instanceof Ticket) && (this.compareTo((Ticket) o) == 0);
}
注意compareTo
的结构:它有多个return
语句,但事实上,逻辑流程非常易读。另请注意,排序标准的优先级是如何明确的,如果您考虑到不同的优先级,则可以轻松重新排序。
答案 1 :(得分:4)
如果你的compareTo方法不一致,可能会发生这种情况。即如果a.compareTo(b) > 0
,那么b.compareTo(a)
必须是&lt; 0.如果a.compareTo(b) > 0
和b.compareTo(c) > 0
,那么a.compareTo(c)
必须是&gt;如果那些不是真的,TreeSet会让所有人感到困惑。
答案 2 :(得分:3)
首先,如果您使用的是TreeSet
,则hashCode
方法的实际行为不会影响结果。 TreeSet
不依赖于散列。
我们真的需要看到更多代码;例如equals
和compareTo
方法的实际实现,以及实例化TreeSet
的代码。
但是,如果我猜测,那就是重载 equals
方法,方法是使用签名boolean equals(Ticket other)
进行声明。这会导致你所看到的行为。要获得所需的行为,您必须覆盖方法; e.g。
@Override
public boolean equals(Object other) { ...
(最好放入@Override
注释,以明确该方法覆盖超类中的方法,或在接口中实现方法。如果您的方法实际上不是覆盖,那么你会得到一个编译错误......这将是一件好事。)
修改强>
根据您添加到问题中的代码,问题不是重载与覆盖。 (正如我所说,我只是猜测......)
compareTo
和equals
很可能不正确。由于两种方法的语义都取决于compareTo
类的equals
和Boeking
方法,因此仍然不完全清楚错误的确切位置。
Ticket.compareTo
的第一个if语句看起来非常可疑。看起来return 1;
可能导致t1.compareTo(t2)
和t2.compareTo(t1)
同时返回1
某些机票t1
和t2
...... 绝对是错误的。