Java 当compareto返回0时理解树集

Java 当compareto返回0时理解树集,java,collections,compareto,treeset,sortedset,Java,Collections,Compareto,Treeset,Sortedset,我创建了一个学生类,如下所示: public class Student implements Comparable<Student> { private String firstName; private String lastName; public Student(String firstName, String lastName) { this.firstName = firstName; this.lastName

我创建了一个学生类,如下所示:

public class Student implements Comparable<Student> {

    private String firstName;
    private String lastName;

    public Student(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    // Getters & Setters follow here...

    @Override
    public int compareTo(Student student) {
        int hash = this.firstName.compareTo(student.firstName);
        return hash;
    }

    @Override
    public String toString() {
        return "Student [firstName=" + firstName + ", lastName=" + lastName
                + "]";
    }

}
在我的测试类中,我正在将
Student
对象添加到
TreeSet
,而且我还没有覆盖
hashCode
equals
方法。因此,我希望
树集
将容纳所有4个对象,但我也可以看到它包含3个对象。你能解释一下为什么新生(“A1”、“B2”)不是我的
树集的一部分吗

此外,根据此处的说明,它说:

如果指定的元素尚未存在,则将其添加到此集合。 更正式地说,如果集合 不包含(e==null?e2==null:e.equals(e2))的元素e2。 如果此集合已经包含该元素,则调用将离开该集合 未更改并返回false

由于我没有重写
equals
方法,那么为什么集合没有包含所有四个元素?

如所述:

TreeSet实例使用其compareTo(或compare)方法执行所有元素比较,因此,从集合的角度来看,此方法认为相等的两个元素是相等的


很荣幸。

您的树集键值是“A1”、“B1”、“A1”、“A2”。即使您不重写等值和哈希代码,但“A1”的默认哈希代码将是相同的,因此树集将把该密钥视为重复密钥,因此您将无法进入“A1”、“B2”< /P> < P>,这是因为<代码>树集使用<代码> CuasReto < /C> >(或<代码>比较器。测试两个元素是否相等。这就是医生们所说的

请注意,如果要正确实现set接口,set维护的顺序(无论是否提供显式比较器)必须与equals一致。(请参阅Comparable或Comparator以获得与equals一致的精确定义。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用其compareTo(或compare)方法执行所有元素比较,因此此方法认为相等的两个元素是,从集合的角度来看,相等。即使集合的顺序与equals不一致,集合的行为也是定义良好的;它只是没有遵守Set接口的总合同


因为在compareTo方法中只比较了第一个名字,所以需要

 @Override
public int compareTo(Student student) {
    int comp = this.firstName.compareTo(student.firstName);
    if(comp==0) return this.lastName.compareTo(student.lastName);
    return comp;
}

当compareTo返回0时,treeSet假设它是重复的。

虽然这个问题已经很老了,但这里有一个非常重要的问题需要理解,大多数人在实现时忽略了这一点

TreeSet
不会将新元素与
集中的所有现有元素进行比较。它使用二进制搜索技术。因此,如果您的输入元素等于一个现有元素(根据
compareTo
契约),并且该元素位于
树的左侧,并且您的
compareTo
方法的实现方式强制新元素位于
树的右侧,您的
TreeSet
不会拒绝新元素,即使新元素中已经存在相同的元素(根据
compareTo
合同)。让我们看看下面的简单示例

我需要对属性为
key
priority
项进行排序

package com.manish;
import java.util.TreeSet;
public class Main {
    static class Item implements Comparable<Item> {
        private long key;
        private int priority;
        public Item(long key, int priority) {
            super();
            this.key = key;
            this.priority = priority;
        }

        /*
         * Items should be treated equal if Keys are equal.
         * Higher priority item should be treated as greater item.
         * If priorities are same, lower key value item should be
         * treated as greater item.
         */
        @Override
        public int compareTo(Item o) {
            if (this.key == o.key) {
                return 0;
            }
            if (this.priority != o.priority) {
                return this.priority - o.priority;
            } else {
                return this.key < o.key ? 1 : -1;
            }
        }
        @Override
        public String toString() {
            return "Item [key=" + key + ", priority=" + priority + "]";
        }
    }
    public static void main(String[] args) {
        TreeSet<Item> set = new TreeSet<>();
        set.add(new Item(2, 1));
        set.add(new Item(4, 3));
        set.add(new Item(3, 1)); //line 1
        set.add(new Item(3, 2)); //line 2. Same item as Item(3,1)
        while (!set.isEmpty())
            System.out.println(set.pollFirst());
    }
}
但是,如果您交换
第1行
第2行
代码,输出将更改如下

Item [key=2, priority=1]
Item [key=3, priority=2]
Item [key=4, priority=3]

我想这是因为您的
compareTo()
。@Gosu,compareTo只是基于
firstName
进行比较,但为什么我不允许添加两个具有相同名字但不同姓氏的对象?可能重复虽然此处引用的摘要包含信息,但TreeSet.add()的文档不幸的是,它不正确,因为它没有提到compareTo。为了确定这一点,我编写了一个单元测试来证明这一点。如果指定的元素尚未存在,则将其添加到此集合。更正式地说,如果集合中不包含元素e2,则将指定的元素e添加到此集合,从而(e==null?e2==null:e.equals(e2))。如果此集合已包含元素,则调用将保持集合不变并返回false这里缺少的一个重要点是TreeSet不能与所有元素进行比较。由于树集是一个排序集,因此它使用二进制搜索技术。这可能导致独特的问题。例如,检查我的答案。
package com.manish;
import java.util.TreeSet;
public class Main {
    static class Item implements Comparable<Item> {
        private long key;
        private int priority;
        public Item(long key, int priority) {
            super();
            this.key = key;
            this.priority = priority;
        }

        /*
         * Items should be treated equal if Keys are equal.
         * Higher priority item should be treated as greater item.
         * If priorities are same, lower key value item should be
         * treated as greater item.
         */
        @Override
        public int compareTo(Item o) {
            if (this.key == o.key) {
                return 0;
            }
            if (this.priority != o.priority) {
                return this.priority - o.priority;
            } else {
                return this.key < o.key ? 1 : -1;
            }
        }
        @Override
        public String toString() {
            return "Item [key=" + key + ", priority=" + priority + "]";
        }
    }
    public static void main(String[] args) {
        TreeSet<Item> set = new TreeSet<>();
        set.add(new Item(2, 1));
        set.add(new Item(4, 3));
        set.add(new Item(3, 1)); //line 1
        set.add(new Item(3, 2)); //line 2. Same item as Item(3,1)
        while (!set.isEmpty())
            System.out.println(set.pollFirst());
    }
}
Item [key=3, priority=1]
Item [key=2, priority=1]
Item [key=3, priority=2]
Item [key=4, priority=3]
Item [key=2, priority=1]
Item [key=3, priority=2]
Item [key=4, priority=3]