比较时理解TreeSet返回0

时间:2015-07-10 07:14:26

标签: java treeset

我创建了一个这样的Student类:

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
                + "]";
    }

}

这是我的测试类,我只是在我的TreeSet中添加元素:

public class SortedSetExample1 {
    public static void main(String[] args) {
        SortedSet<Student> set = new TreeSet<Student>();
        set.add(new Student("A1","A2"));
        set.add(new Student("B1","B2"));
        set.add(new Student("A1","B2"));
        set.add(new Student("A2","B2"));
        System.out.println(set);
    }
}

根据我的程序,输出为:

[Student [firstName=A1, lastName=A2], Student [firstName=A2, lastName=B2], Student [firstName=B1, lastName=B2]]

在我的测试课程中,我将Student个对象添加到TreeSet,而且我还没有覆盖hashCode&amp; equals方法。所以我期待TreeSet将保存所有4个对象,但我也可以看到它包含3个对象。您能否解释为什么new Student("A1","B2")不属于我的TreeSet

此外,根据此处的Java docs for TreeSet,它说:

  

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

由于我没有覆盖equals方法,为什么该集合没有所有四个元素?

5 个答案:

答案 0 :(得分:10)

正如java.util.TreeSet所说:

  

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

感谢@Jon Skeet

答案 1 :(得分:1)

这是因为TreeSet使用compareTo(或Comparator.compare)来测试两个元素是否相等。这就是文档所说的内容。

  

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

答案 2 :(得分:1)

由于您只比较了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假定它是重复的。

答案 3 :(得分:0)

尽管问题已经很老了,但这是了解大多数人在实施过程中忽略哪些问题的非常重要的一点。

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

我需要对key个具有prioritypackage 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]

输出:

line 1

但是,如果交换line 2Item [key=2, priority=1] Item [key=3, priority=2] Item [key=4, priority=3] 代码,则输出将更改如下。

 Dim SUMrow As Long
    Dim Arg1 As Variant
    Dim Arg2 As Range
    Dim Arg3 As Range
    Dim sumvalue As String
   Dim ws As Worksheet
    For SUMrow = 2 To 99999
        If (Workbooks("ExpenseDataMcframe.xlsm").Worksheets("ImportData2").Range("b" & SUMrow) = "") Then Exit For

               Set Arg1 = Workbooks("ExpenseDataMcframe.xlsm").Worksheets("ImportData2").Range("L:L")
               Set Arg2 = Workbooks("ExpenseDataMcframe.xlsm").Worksheets("ImportData2").Range("B:B")
                Set Arg3 = Workbooks("ExpenseDataMcframe.xlsm").Worksheets("ImportData2").Range("C:C")

                 'sumvalue = WorksheetFunction.SUMIFS(L:L,B:B,B:B,C:C,C:C)
              '   sumvalue = Application.WorksheetFunction.SumIfs(Arg1, Arg2, Arg2, Arg3, Arg3)
                 Set ws = Workbooks("ExpenseDataMcframe.xlsm").Worksheets("ImportData2")
                    'apply the Excel SUMIF function
                sumvalue = WorksheetFunction.SumIfs(ws.Range("L:L"), ws.Range("B:B"), ws.Range("B:B"), ws.Range("C:C"), ws.Range("C:C"))

                 Workbooks("ExpenseDataMcframe.xlsm").Worksheets("ImportData2").Range("N" & SUMrow).Value = sumvalue

         'End If
        'End If
    Next

答案 4 :(得分:-1)

嗯,你的树形键值是&#34; A1&#34;,&#34; B1&#34;,&#34; A1&#34;,&#34; A2&#34;。即使你没有覆盖equals和hashcode仍然是&#34; A1&#34;的默认哈希码。将是相同的,因此树集会将此密钥视为重复密钥,因此您将无法输入&#34; A1&#34;,&#34; B2&#34;