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

我在表单中有几个数组:

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

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

 TreeSet patTreeSet = new TreeSet(); 

患者是另一类产生“患者”对象的人。 然后我遍历我的数组中的每个元素来创建几个患者并将它们添加到我的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 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()方法

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

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

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

TreeSet的Javadoc说:

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

实现这一目标的最简单方法是让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; } 

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

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

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

此外,如果任何字段可以为null ,则还需要检查它。