Treeset.contains()问题

Jas*_*per 10 java contains treeset

所以我现在一直在努力解决问题,我想在这里也可以寻求帮助.

我将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));
Run Code Online (Sandbox Code Playgroud)

返回:

22106622
22106622
true
0
false
Run Code Online (Sandbox Code Playgroud)

现在我的问题是这甚至可能如何?

编辑:

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
Run Code Online (Sandbox Code Playgroud)

pol*_*nts 18

compareTo合同上

问题出在你的身上compareTo.以下是文档的摘录:

实施者必须确保sgn(x.compareTo(y)) == -sgn(y.compareTo(x))所有人xy.

您的原始代码在此处复制以供参考:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

为什么是return 1;一个bug?请考虑以下情形:

  • 特定 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
Run Code Online (Sandbox Code Playgroud)

相反,声明这样的事情会更合适:

// improved declaration! uses parameterized Comparable<T>
public class Ticket implements Comparable<Ticket>
Run Code Online (Sandbox Code Playgroud)

现在我们可以写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;
   }
}
Run Code Online (Sandbox Code Playgroud)

现在我们也可以equals(Object)compareTo(Ticket)而不是相反的方式来定义:

@Override public boolean equals(Object o) {
   return (o instanceof Ticket) && (this.compareTo((Ticket) o) == 0);
}
Run Code Online (Sandbox Code Playgroud)

注意compareTo:它有多个return语句的结构,但事实上,逻辑流程是可读的.另请注意,如果您考虑到不同的优先,排序标准的优先级如何是明确的,并且可以轻松重新排序.

相关问题