Treeset.contains () проблема

Таким образом, я боролся с проблемой некоторое время теперь, полагали, что я мог бы также обратиться за помощью здесь.

Я добавляю, что Билет возражает против TreeSet, Билет реализует Сопоставимый и переопределил, равняется (), хэш-код () и CompareTo () методы. Я должен проверить, находится ли объект уже в использовании TreeSet, содержит (). Теперь после добавления 2 элементов к набору все это проверяет прекрасный, все же после добавляющей одной трети, это испорчено.

выполняя этот маленький кусочек кода после добавления третьего элемента к TreeSet, Билет 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
10
задан Jasper 8 August 2010 в 02:13
поделиться

3 ответа

В контракте compareTo

Проблема заключается в вашем compareTo . Вот выдержка из документации :

Разработчик должен обеспечить 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; является ошибкой? Рассмотрим следующий сценарий:

  • Дано Билет t1, t2
  • Дано t1.boeking.compareTo (t2.boeking) == 0
  • Дано t1.equals (t2) return false
  • Теперь у нас есть оба из следующего:
    • t1.compareTo (t2) возвращает 1
    • t2.compareTo (t1) возвращает 1

Последнее последствие - нарушение контракт compareTo .


Устранение проблемы

Прежде всего, вы должны были воспользоваться тем фактом, что Comparable является параметризуемым универсальным типом. То есть, вместо:

// 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 , но на самом деле логика вполне читаема.Также обратите внимание на то, что приоритет критериев сортировки является явным и легко переупорядочивается, если вы имеете в виду другие приоритеты.

Связанные вопросы

18
ответ дан 3 December 2019 в 16:28
поделиться

Это могло произойти, если ваш метод compareTo несовместим. Т.е. если a.compareTo (b)> 0 , то b.compareTo (a) должно быть <0. И если a.compareTo (b)> 0 и b.compareTo (c)> 0 , тогда a.compareTo (c) должно быть> 0. Если это не так, TreeSet может запутаться.

4
ответ дан 3 December 2019 в 16:28
поделиться

Во-первых, если вы используете TreeSet , фактическое поведение ваших методов hashCode не повлияет на результаты. TreeSet не зависит от хеширования.

На самом деле нам нужно увидеть больше кода; например фактическая реализация методов equals и compareTo и кода, который создает экземпляр TreeSet .

Однако, если я предполагаю, это будет так, что вы перегрузили метод равно , объявив его с помощью сигнатуры логического равенства (Ticket other) . Это приведет к тому поведению, которое вы наблюдаете.Чтобы получить требуемое поведение, вы должны переопределить метод; например

@Override
public boolean equals(Object other) { ...

(Рекомендуется добавить аннотацию @Override , чтобы было ясно, что метод переопределяет метод в суперклассе или реализует метод в интерфейсе. Если ваш метод не на самом деле переопределение, тогда вы получите ошибку компиляции ... что было бы хорошо.)

РЕДАКТИРОВАТЬ

Исходя из кода, который вы добавили в вопрос, проблема не в перегрузке и переопределении. (Как я уже сказал, я только догадывался ...)

Скорее всего, compareTo и равно неверны. По-прежнему не совсем ясно, где именно находится ошибка, поскольку семантика обоих методов зависит от методов compareTo и равно класса Boeking .

Первый оператор if в Ticket.compareTo выглядит очень подозрительно. Похоже, что return 1; может привести к тому, что t1.compareTo (t2) и t2.compareTo (t1) оба вернут 1 для некоторых билетов t1 и t2 ... и это определенно будет неправильным.

3
ответ дан 3 December 2019 в 16:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: