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

时间:2014-03-02 03:02:32

标签: java set treeset

我在表单中有几个数组:

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

然后我创建一个这样的TreeSet:

TreeSet<Patient> patTreeSet = new TreeSet<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);
}

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

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

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

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

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

}

然后只有“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;
    }

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

1 个答案:

答案 0 :(得分:15)

如果将对象放在TreeSet中,则需要在构造函数中提供Comparator接口的实现,或者您需要将对象作为实现{{1}的类}}。

您说您是从Comparable界面实施compareTo,但在您的评论中,您说您没有,所以我认为您只是Comparable在{ {1}}方法?这可以解释您的问题,因为TreeSet会根据return 0;方法结果认为您的所有对象都是“相同的”。

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

compareTo的Javadoc说:

  

注意由一组维护的排序(无论是否显式   比较器提供)必须与equals 一致,如果是的话   正确实现TreeSet接口。

实现这一目标的最简单方法是让TreeSet方法调用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; } 上阅读(Javadoc或书籍)以及TreeSetHashSetequals方法的重要性。 如果您想将对象放在Set或Map中,您需要了解这些对象才能正确实现。

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

java.util.Date

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