[英]Java Collections.sort() not sorting as expected
我試圖通過特定的屬性(“程序”的“學生”對象和“教師”的“教授”對象)對對象的兩個不同的數組列表進行排序。 這兩個類都擴展了我的抽象'Person'類。
public abstract class Person implements Comparable<Person>{
private String name;
private String adress;
//getters, setters, etc., all works properly
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int compareTo(String string) {
return name.compareTo(string);
}
}
然后,當我創建一個1000000個隨機“人物”對象的數組而不是學生或教授時,我決定按照它們的名字(按字母順序)按字母順序排序(它可以正常工作)。
Person personByName[] = arrayPersonas.clone();
Arrays.sort(personByName);
然后,我將原始Person數組分成兩個ArrayLists,一個用於Student對象,另一個用於Professor對象:
ArrayList<Student> studentsByProgram = new ArrayList();
ArrayList<Professor> professorsByFaculty = new ArrayList();
for (int i = 0; i < 1000000; i++) {
if (arrayPersonas[i] instanceof Student) {
studentsByProgram.add((Student)arrayPersonas[i]);
} else {
professorsByFaculty.add((Professor)arrayPersonas[i]);
}
}
當我嘗試按照我想要的屬性按字母順序對每個ArrayList進行排序時會出現問題,因為它會按Person的名稱對它們進行排序:
Collections.sort(studentsByProgram);
Collections.sort(professorsByFaculty);
在這里,我留下我的學生和教授課程:
public class Student extends Person {
private String program;
private int year;
private double fee;
//constructor, setters, getters, toString, equals
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int compareTo(String string) {
return program.compareTo(string);
}
@Override
public int compareTo(Person t) {
return super.compareTo(t.getName());
}
}
教授班:
public class Professor extends Person {
private String faculty;
private double salary;
//constructor, setters, getters, toString, equals
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int compareTo(String string) {
return faculty.compareTo(string);
}
@Override
public int compareTo(Person t) {
return super.compareTo(t.getName());
}
}
我究竟做錯了什么? 我想如果我在Student對象的ArrayList上調用“Collections.sort()”,它將使用我的Student類中的“compareTo()”方法,該方法使用“program”屬性。 我還在學習使用這些方法,所以有些東西我沒有得到。
您有兩個不同的compareTo()方法。 您期望使用的那個不會被Collections.sort()調用。
如果你想使用Collections.sort()對學生進行排序,那么你需要一個帶簽名compareTo(學生)的方法;
這個方法與compareTo(Person person)“重疊”,這是兩個問題:
在語義上,Person級別的compareTo()方法建立了語義 ,而Student級別的compareTo()方法偏離了那些語義,這從來都不是一個好主意。
從技術上講,您依賴於與方法綁定相關的實現細節,以使您的系統按照需要運行。 這充其量是狡猾的。
我會尋找一種排序方法,它使用顯式的用戶提供的比較器,而不是依賴於內部compareTo()的排序方法。
Person
對象。 Student
和Professor
實例。 compareTo(String)
,這些方法具有誤導性。 正確定義Person#compareTo
,刪除其compareTo(String)
:
public int compareTo(Person p) { return getName().compareTo(p.getName()); }
正確定義Student#compareTo
和Professor#compareTo
,刪除他們的compareTo(String)
。 以下是Student#compareTo
如何編寫的示例:
@Override public int compareTo(Person t) { final int personComparisonResult = super.compareTo(t); if (personComparisonResult == 0) { return program.compareTo(((Student) t).program); } return personComparisonResult; }
它說“將它們作為第一Person
進行比較;如果它們是相同的(這里,具有相同的名稱),將它們作為Student
(在這里,通過學生的程序)進行比較”。
我會刪除這些方法。 對於不適合類域的簡單代碼行,不值得使用單獨的方法。
如果要使用不同的順序將對象排序為“自然”排序類,則應使用Arrays.sort(T[], Comparator<T>)
,以及實現特定排序順序或排序的Comparator
對象。
Comparable
的javadoc解釋了它應該實現的語義。 (仔細閱讀!)
關於自然排序:
Person[]
的“自然”排序將由compareTo(Person)
方法給出。 Student[]
(或ArrayList<Student>
)的“自然”排序將由compareTo(Student)
方法給出。 compareTo(String)
方法! 類Person
中的compareTo(String)
方法沒有多大意義,因為它this
(一個Person
)與一個String
進行了比較。 特別是它對由Person
類實現的Comparable<Person>
接口沒有貢獻。
您應該this
(一個Person
)與另一個Person
:
@Override
public int compareTo(Person otherPerson) {
return name.compareTo(otherPerson.name);
}
然后,在您的班級Professor
和Student
您可以使用上述方法,如下所示:
@Override
public int compareTo(Person otherPerson) {
return super.compareTo(otherPerson);
}
其實,不需要這種方法了,因為它的行為是一樣compareTo(Person)
的Person
。 您可以省略此方法,但仍具有相同的效果。
這是用Effective Java書提醒自己的好時機第40項:始終如一地使用Override。
您的基類Person不會在compareTo方法上使用@Override表示法,因此如果您實際上沒有覆蓋您認為的compareTo方法,則不會出現錯誤。 在這種情況下,參數類型是錯誤的。 它應該是Person,而不是String。 不調用該方法,而是使用默認開啟。
-我
我相信當您想要在特定屬性上對類進行排序時,您需要使用比較器。
嘗試類似的東西:
static final Comparator<Student> compareProgram = new Comparator<Student>() {
public int compare(Student e1, Student e2) {
//condition ( you need to return the condition)
return e2.program().compareTo(e1.program());
}
};
// Employee database
static final Collection<Student> students = ... ;
public static void main(String[] args) {
List<Student> e = new ArrayList<Student>(students);
Collections.sort(e, compareProgram);
System.out.println(e);
}
比較器是一個存在於集合下的函數,因此您只需插入要查找的條件即可。
如果您無法實現它,請告訴我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.