Java 为什么我的 TreeSet 没有在第一个元素之外添加任何内容?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22123336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:45:36  来源:igfitidea点击:

Why does my TreeSet not add anything beyond the first element?

javasettreeset

提问by Jona

I have several arrays in the form:

我有几个数组的形式:

private static String[] patientNames = { "John Lennon", "Paul McCartney", "George Harrison", "Ringo Starr" };

Then I make a TreeSet like this:

然后我像这样制作一个 TreeSet:

TreeSet<Patient> patTreeSet = new TreeSet<Patient>();

Where Patient is a different class that makes "Patient" objects. Then I loop through each element in my arrays to create several patients and add them to my patTreeSetlike this:

其中 Patient 是一个不同的类,它创建“Patient”对象。然后我遍历数组中的每个元素以创建几个患者并将它们添加到我的patTreeSet像这样:

for(int i = 0; i< patientNames.length; i++){
     Date dob = date.getDate("MM/dd/yyyy", patientBirthDates[i]);
     Patient p = new PatientImpl(patientNames[i], patientSSN[i], dob);

     patTreeSet.add(p);
}

But when I go to check my patTreeSet.size()it only returns "1" - why is this?

但是当我去检查patTreeSet.size()它时它只返回“1”——这是为什么?

I know my objects are working well because when I try to do the same thing but with ArrayListinstead, everything works fine. So I'm guessing I'm using the TreeSet wrong.

我知道我的对象运行良好,因为当我尝试做同样的事情但ArrayList相反,一切正常。所以我猜我使用 TreeSet 是错误的。

If it helps, Patient has a method called getFirstName(), and when I try to do the following:

如果有帮助,Patient 有一个名为 getFirstName() 的方法,当我尝试执行以下操作时:

Iterator<Patient> patItr = patTreeSet.iterator();

while(patItr.hasNext()){
    System.out.println(patItr.next().getFirstName());

}

Then only "John" prints, which obviously shouldn't be the case... So, am I totally misusing the TreeSet?

然后只有“John”打印,这显然不应该是这种情况......那么,我是否完全误用了 TreeSet?

Thanks in advance for any help!

在此先感谢您的帮助!

EDITbelow

在下面编辑

================PatientImpl Class====================

================PatientImpl 类====================

public class PatientImpl implements Patient, Comparable{

    Calendar cal = new GregorianCalendar();
    private String firstName;
    private String lastName;
    private String SSN;
    private Date dob;
    private int age;
    private int thisID;             
    public static int ID = 0;       



    public PatientImpl(String fullName, String SSN, Date dob){

        String[] name = fullName.split(" ");
        firstName = name[0];
        lastName = name[1];

        this.SSN = SSN;

        this.dob = dob;

        thisID = ID += 1;
    }

@Override
    public boolean equals(Object p) {

        //for some reason casting here and reassigning the value of p doesn't take care of the need to cast in the if statement...
        p = (PatientImpl) p;

        Boolean equal = false;
        //make sure p is a patient before we even compare anything
        if (p instanceof Patient) {

            Patient temp = (Patient) p;

            if (this.firstName.equalsIgnoreCase(temp.getFirstName())) {
                if (this.lastName.equalsIgnoreCase(temp.getLastName())) {
                    if (this.SSN.equalsIgnoreCase(temp.getSSN())) {
                        if(this.dob.toString().equalsIgnoreCase(((PatientImpl) p).getDOB().toString())){
                            if(this.getID() == temp.getID()){
                                equal = true;
                            }
                        }
                    }
                }
            }
         }
        return equal;
    }

and then all the getters are below, as well as the compareTo() method from the Comparable interface

然后所有的 getter 都在下面,以及 Comparable 接口中的 compareTo() 方法

采纳答案by Erwin Bolwidt

If you put your objects in a TreeSet, you need to either provide an implementation of the Comparatorinterface in the constructor, or you need your objects to be of a class that implements Comparable.

如果将对象放在 a 中TreeSet,则需要Comparator在构造函数中提供接口的实现,或者需要对象属于实现 的类Comparable

You said you implement compareTofrom the Comparableinterface, but in your comment you say that you didn't, so am I correct in assuming that you just return 0;in the compareTomethod? That would explain your problem, because TreeSet would then think that all your objects are 'the same' based on the compareTomethod result.

你说你compareToComparable接口实现,但在你的评论中你说你没有,所以我假设你只是return 0;compareTo方法中是正确的吗?这可以解释您的问题,因为 TreeSet 会根据compareTo方法结果认为您的所有对象都是“相同的” 。

Basically, in a TreeSet, your objects are maintained in a sorted order, and the sorting is determined by the outcome of the Comparable/Comparator method. This is used to quickly find duplicates in a TreeSet and has the added benefit that when you iterate over the TreeSet, you get the results in sorted order.

基本上,在 a 中TreeSet,您的对象按排序顺序维护,排序由 Comparable/Comparator 方法的结果决定。这用于快速查找 TreeSet 中的重复项,并具有额外的好处,即当您遍历 TreeSet 时,您可以按排序顺序获得结果。

The Javadoc of TreeSetsays:

的 JavadocTreeSet说:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equalsif it is to correctly implement the Setinterface.

请注意,如果要正确实现接口,则集合维护的排序(无论是否提供显式比较器)必须与 equals 一致Set

The easiest way to achieve that is to let your equalsmethod call the compareTomethod and check if the result is 0.

实现这一目标的最简单方法是让您的equals方法调用该compareTo方法并检查结果是否为0.

Given your PatientImplclass, I assume that you would want to sort patients first by their last name, then by their first name, and then by the rest of the fields in the class.

鉴于您的PatientImpl班级,我假设您希望首先按姓氏对患者进行排序,然后按他们的名字排序,然后按班级中的其余字段排序。

You could implement a compareTomethod like this:

你可以实现一个compareTo这样的方法:

@Override
public int compareTo(Object o) {
    if (!(o instanceof Patient))
        return -1;
    Patient temp = (Patient) o;
    int r = this.lastName.compareToIgnoreCase(temp.getLastName());
    if (r == 0)
        r = this.firstName.compareToIgnoreCase(temp.getFirstName());
    if (r == 0)
        r = this.SSN.compareToIgnoreCase(temp.getSSN());
    if (r == 0)
        r = this.dob.toString().compareToIgnoreCase(temp.getDOB().toString());
    if (r == 0)
        r = Integer.compare(this.getID(), temp.getID());
    return r;
}

I believe that would solve the problem you described. I would advise you to read up (Javadoc or books) on TreeSetand HashSetand the importance of the equals, compareToand hashCodemethods. If you want to put your objects in a Set or a Map, you need to know about these to implement that correctly.

我相信这会解决你描述的问题。我建议您阅读(Javadoc 或书籍)TreeSet和,和方法HashSet的重要性。如果你想把你的对象放在一个 Set 或一个 Map 中,你需要了解这些才能正确地实现它。equalscompareTohashCode

NoteI based this compareTomethod on your equalsmethod. You were comparing the date-of-birth by first calling toString. That's not a very good way of doing that - you can use the equalsmethod in java.util.Date directly. In a compareTo method the problem gets worse because dates do not sort correctly when you sort them alphabetically. java.util.Datealso implements Comparableso you can replace that comparison in the method with:

注意我根据compareTo你的equals方法建立了这个方法。您是通过首先调用 toString 来比较出生日期的。这不是一个很好的方法 - 您可以equals直接使用java.util.Date 中的方法。在 compareTo 方法中,问题变得更糟,因为当您按字母顺序排序日期时,日期排序不正确。 java.util.Date也实现了,Comparable因此您可以将方法中的比较替换为:

    if (r == 0)
        r = this.dob.compareTo(temp.getDOB());

In addition, if any of the fields could be null, you need to check for that as well.

此外,如果任何字段可能是null,您也需要检查它。