为什么我的TreeSet不会添加除第一个元素之外的任何内容?

Jon*_*ona 6 java set treeset

我在表单中有几个数组:

private static String[] patientNames = { "John Lennon", "Paul McCartney", "George Harrison", "Ringo Starr" };
Run Code Online (Sandbox Code Playgroud)

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

TreeSet<Patient> patTreeSet = new TreeSet<Patient>();
Run Code Online (Sandbox Code Playgroud)

患者是另一类产生"患者"对象的人.然后我遍历我的数组中的每个元素来创建几个患者并将它们添加到我的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);
}
Run Code Online (Sandbox Code Playgroud)

但是当我去检查我的patTreeSet.size()时候它只返回"1" - 这是为什么?

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

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

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

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

}
Run Code Online (Sandbox Code Playgroud)

然后只有"John"打印,显然不应该这样......所以,我是否完全滥用TreeSet?

在此先感谢您的帮助!

编辑如下

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

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;
    }
Run Code Online (Sandbox Code Playgroud)

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

Erw*_*idt 16

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

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

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

Javadoc TreeSet说:

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

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

鉴于你的PatientImpl课程,我假设你想要先用姓氏,然后用他们的名字,然后是课堂上的其他字段对患者进行排序.

你可以实现这样的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;
}
Run Code Online (Sandbox Code Playgroud)

我相信这可以解决你所描述的问题.我会建议你阅读了关于(Javadoc中或书籍)TreeSetHashSet和的重要性equals,compareTohashCode方法.如果要将对象放在Set或Map中,则需要了解这些对象才能正确实现.

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

    if (r == 0)
        r = this.dob.compareTo(temp.getDOB());
Run Code Online (Sandbox Code Playgroud)

此外,如果有任何字段null,您还需要检查它.

  • @jayeffkay 你是对的,有趣的是,这已经 3 年没有被发现了。我还更新了 id 的比较 - 使用 Integer.compare 比减法更好,因为它避免了可能的整数溢出情况。 (2认同)