当整个学生对象是唯一的时,为什么 TreeSet 不能有相似的学生年龄?

Why can't TreeSet have student ages similar when the whole student object is unique?

我有一个数据类型StudentSet。它接受姓名和年龄。当我将此添加到 TreeSet 时,不会添加年龄相似的学生。我知道 TreeSet 只添加唯一性,但我有不同的学生名字,所以总的来说 StudentSet 不是唯一性的吗?我想知道这背后的原因。

以下是我的代码

import java.util.Comparator;
import java.util.TreeSet;

public class StudentSet implements Comparable<StudentSet> {
    String name;
    int age;

    public StudentSet(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student[Name= " + name + "," + " Age= " + age + "]";
    }


    public static void main(String[] args) {
        TreeSet<StudentSet> set = new TreeSet<>();
        set.add(new StudentSet("xyz", 21));
        set.add(new StudentSet("abc", 23));
        set.add(new StudentSet("xyxyxr", 24));
        System.out.println(set.add(new StudentSet("aaaaaa", 20))); //prints false
        System.out.println(set.add(new StudentSet("bbbbbb", 20))); //prints false
        System.out.println(set.add(new StudentSet("cccc", 20))); //prints false

        TreeSet<StudentSet> sort = new TreeSet<>(new Comparator<StudentSet>() {
            @Override
            public int compare(StudentSet o1, StudentSet o2) {
                return o1.name.compareTo(o2.name);
            }
        });

        sort.addAll(set);
        System.out.println("Sorting According to Name\n");
        for (StudentSet s : sort) {
            System.out.println(s);
        }
        System.out.println();

        sort = new TreeSet<>(new Comparator<StudentSet>() {
            @Override
            public int compare(StudentSet o1, StudentSet o2) {
                return o1.compareTo(o2);
            }
        });

        System.out.println("Sorting According to Age\n");
        sort.addAll(set);
        for (StudentSet s : sort) {
            System.out.println(s);
        }
        System.out.println();

        sort = new TreeSet<>(new Comparator<StudentSet>() {
            @Override
            public int compare(StudentSet o1, StudentSet o2) {
                int lastIndex1 = o1.name.lastIndexOf(" ");
                int lastIndex2 = o2.name.lastIndexOf(" ");

                String lastName1 = o1.name.substring(lastIndex1);
                String lastName2 = o2.name.substring(lastIndex2);
                if (lastName1.equals(lastName2)) {
                    return o1.name.compareTo(o2.name);
                } else {
                    return lastName1.compareTo(lastName2);
                }
            }
        });

        System.out.println("Sorting According to Last Name\n");
        sort.addAll(set);
        for (StudentSet s : sort) {
            System.out.println(s);
        }
    }

    @Override
    public int compareTo(StudentSet o) {
        return ((Integer) this.age).compareTo(o.age);
    }
}

更新:

罪魁祸首是我在 StudentSet 中设置了 compareTo() 方法来比较年龄,TreeSet 在内部使用它来比较和检查唯一性。

这是我更正并满意的代码。

@Override
public int compareTo(StudentSet o)
{
    int i = Integer.compare(this.age, o.age);
    if (i == 0)
        return this.name.compareTo(o.name);
    else
        return i;
}

重新定义你的 compareTo 方法,StudentSet 是你自己的自定义对象,所以通过实现 Comparable 接口,你告诉编译器在你的实现之后添加到 TreeSet .

下面的实现说,如果两个或更多 StudentSet 中的 age 相同,则它们 唯一 相等。

@Override
public int compareTo(StudentSet o)
{
    return ((Integer) this.age).compareTo(o.age);
}

修改实现如下,

@Override
    public int compareTo(StudentSet o)
    {
         int i = ((Integer) this.age).compareTo(o.age);
            if (i == 0)
                return this.name.compareTo(o.name);
            else
               return i;
    }

以上将检查两者 Age and Name,如果相同,则您的对象是唯一的。

您正在创建 4 个 TreeSet 个实例,每个实例都有不同的 Comparator。传递给 TreeSetComparator 确定两个元素是否被认为是相同的。

在第一个 TreeSet 中,您没有将任何 Comparator 传递给构造函数,这意味着使用了自然顺序(由 Comparable 定义)。 ComparablecompareTo 仅按年龄进行比较。

在第三个 TreeSet 中,您正在使用此 compare 方法:

    @Override
    public int compare(StudentSet o1, StudentSet o2)
    {
        return o1.compareTo(o2);
    }

由于compareTo只比较年龄,两个年龄相同的StudentSet实例被认为是相同的,只有其中一个会被添加到TreeSet

如果您希望您的原始 set TreeSet 以及分配给 sort 变量的 3 TreeSet 包含所有唯一元素,您的所有 comparecompareTo 方法必须按确定唯一 StudentSet 实例的所有属性排序。

他们可以通过每次以不同的顺序比较属性,使用不同的顺序对 TreeSet 进行排序。比如可以先比名字再比年龄(如果名字相等),也可以先比年龄再比名字(如果年龄相等)。

根据 compareTo 方法的实施,它工作正常。如果你想让它基于 name 而不是 ages 那么你需要在 compareTo 方法中更正它,如下所示,

@Override
public int compareTo(StudentSet o)
{
    return this.name.compareTo(o.name);
    //return ((Integer) this.age).compareTo(o.age);
}