I am trying to sort two different ArrayLists of objects by a specific atribute ('Student' objects by "program" and 'Professor' objects by "faculty"). Both classes extend my abstract 'Person' class.
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);
}
}
Then, when I create an array of 1000000 random 'Person' objects than can be Students or Professors, I decide to sort it alphabetically by their name like this (which works properly).
Person personByName[] = arrayPersonas.clone();
Arrays.sort(personByName);
Then, I divide the original Person array into two ArrayLists, one for Student objects and another for Professor objects:
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]);
}
}
The problem comes when i try to sort each ArrayList alphabetically by the atribute I want, since it keeps sorting them by the name of the Person:
Collections.sort(studentsByProgram);
Collections.sort(professorsByFaculty);
Here I leave my Student and Professor classes:
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());
}
}
Professor class:
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());
}
}
What am I doing wrong? I thought if I call "Collections.sort()" on an ArrayList of Student objects it would use the "compareTo()" method from my Student class, which uses the "program" atribute. I'm still learning to work with these methods so there is something I'm not getting.
Yes, the Collections. sort methods are only for lists. You can't sort HashSet , but a TreeSet is automatically sorted as you add items, and LinkedHashSet is sorted by insertion order. Show activity on this post.
This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort. The specified list must be modifiable, but need not be resizable.
No, Collections. sort will sort everything, using an Unicode ordinal lexicographic comparison as that's the behaviour of String.
It works on array input. Collections. sort() can sort objects on both contiguous and discrete memory locations: i.e. it can work on both ArrayList and LinkedList . Collections.
You have two distinct compareTo() methods. The one you're expecting to be used does not get invoked by Collections.sort().
If you want orderings on Students using Collections.sort() then you need a method with signature compareTo(Student student);
This method "overlaps" with compareTo(Person person) and that's a problem on two counts :
semantically, the compareTo() method at Person level establishes semantics and your compareTo() method at the Student level deviates from those semantics and that's never a good idea.
technically, you are relying on implementation details related to the method binding to make your system behave as desired. That's dodgy at best.
I'd look out for a sorting method that uses an explicit user-provided comparator instead of a sorting method that relies on internal compareTo().
Person
objects should be compared.Student
and Professor
instances should be compared.compareTo(String)
that are misleading.Define Person#compareTo
properly, remove its compareTo(String)
:
public int compareTo(Person p) {
return getName().compareTo(p.getName());
}
Define Student#compareTo
and Professor#compareTo
correctly, remove their compareTo(String)
. Here's an example of how Student#compareTo
could be written:
@Override
public int compareTo(Person t) {
final int personComparisonResult = super.compareTo(t);
if (personComparisonResult == 0) {
return program.compareTo(((Student) t).program);
}
return personComparisonResult;
}
It says "compare them as Person
s first; if they are equal (here, have the same name), compare them as Student
s (here, by student's program)".
I would remove these methods. It isn't worth having a separate method for a simple line of code which doesn't fit the class domain.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With