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]