Пример TreeSet

Почему 3-й объект не добавляется в набор деревьев, хотя он другой?

import java.util.*;

class Student implements Comparable<Student>{
public String fn,ln;
public Student(String fn,String ln){
    this.fn=fn;
    this.ln=ln;
}

//overiding equals

public boolean equals(Object o) {
    if (!(o instanceof Student))
        return false;
    Student s=(Student) o;
    if(this==s)
        return true;
    if(this.fn.equals(s.fn) && this.ln.equals(s.ln))
        return true;
    return false;
}

//overiding hashcode

public int hashCode() {
    return fn.hashCode()+ln.hashCode();
}


//overiding compareTo

public int compareTo(Student o) {

    return this.fn.compareTo(o.fn);
}
  }

public class Practice {


public static void main(String[] args) {
    Student st1=new Student("Girish","J");
    Student st2=new Student("Master","M");
    Student st3=new Student("Girish","Jay");
    Set S=new TreeSet();

           //adding 3 different student objects

    System.out.println(S.add(st1));
    System.out.println(S.add(st2));
    System.out.println(S.add(st3));
    Iterator sitr=S.iterator();
    while(sitr.hasNext())
    {
        Student stu=(Student) sitr.next();
        System.out.println(stu.fn+" "+stu.ln);
    }


}

 }

Вывод:

true
true
false
Girish J
Master M

person Girish    schedule 18.06.2012    source источник
comment
Set S=new TreeSet();, вероятно, должно быть SortedSet<Student> S=new TreeSet<Student>();.   -  person S.L. Barth    schedule 18.06.2012


Ответы (3)


Ваша функция сравнения использует только fn:

public int compareTo(Student o) {
    return this.fn.compareTo(o.fn);
}

TreeSet только использует сравнение по порядку — не использует hashCode() и equals().

При таком сравнении st1 и st3 равны (s1.compareTo(s3) возвращает 0), поэтому st3 не добавляется в набор.

Если вы хотите сохранить различие, вам, вероятно, следует сравнить fn, а затем использовать ln, если значения fn совпадают:

public int compareTo(Student o) {
    int fnResult = this.fn.compareTo(o.fn);
    return fnResult == 0 ? ln.compareTo(o.ln) : fnResult;
}
person Jon Skeet    schedule 18.06.2012
comment
Спасибо, Джон. во время отладки я заметил, что Treeset не использует hashcode() и equals() для сравнения. Интересный! Так что нет никакого способа, где вы хотите сравнить только имя? - person Girish; 18.06.2012
comment
+1 @Girish, у вас должен быть уникальный идентификатор для Student, потому что может случиться так, что у двух студентов могут быть одинаковые имя и фамилия. - person jmj; 18.06.2012
comment
Ну, вы сравниваете только имя. Это именно то, что он делает, поэтому он отвергает третьего ученика. Непонятно, какие требования вы хотите получить. - person Jon Skeet; 18.06.2012
comment
@Jon: я просто изучал Коллекции, тренируясь. Особых требований как таковых нет. - person Girish; 18.06.2012

Ваши наблюдения верны, что TreeSet не использует .equals и .hashcode для сравнения.

Из javadocs:

This is so because the Set interface is defined in terms of the equals operation, but a 
TreeSet instance performs all element comparisons using its compareTo (or compare) method,
so two elements that are deemed equal by this method are, from the standpoint of the set, 
equal. 

В основном говорят, что для TreeSet равенство определяется не через .equals, а через .compareTo на интерфейсе Comparable. Обратите внимание, что .compareTo всегда должен соответствовать .equals, а это означает, что если a.equals(b), то a.compareTo(b) == 0.

Это связано с тем, что TreeSet является реализацией SortedSet. Таким образом, для определения порядка требуется .compareTo, поскольку в этом случае .equals недостаточно.

PS: Если вы не хотите реализовывать Comparable (что иногда невозможно, поскольку вы не всегда можете контролировать код объектов), вы всегда можете передать Comparator конструктору TreeSet.

person Matt    schedule 18.06.2012

В вашем сравнении используется только значение fn...

public int compareTo(Student o) {
    return this.fn.compareTo(o.fn);
}

Что не удается для третьего Student, потому что первое имя идентично первому Student

Вам нужно настроить свой код, чтобы сравнить значения fn и ln...

public int compareTo(Student o) {
    int firstNameComparison = this.fn.compareTo(o.fn);
    if (firstnameComparison != 0){
        // the first names are different
        return firstNameComparison;
    }
    else {
        // the first names are the same, so compare the last name
        return this.ln.compareTo(o.ln);
    }
}

Этот код сначала сравнивает значения fn. Если они идентичны, он сравнивает значения ln.

person wattostudios    schedule 18.06.2012