Java Collections.sort () не сортируется должным образом - PullRequest
0 голосов
/ 01 октября 2018

Я пытаюсь отсортировать два разных массива объектов по определенному атрибуту (объекты «Студент» по объектам «программа» и «Профессор» по «факультету»).Оба класса расширяют мой абстрактный класс «Персона».

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 на два ArrayList, один для объектов 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 в алфавитном порядке по атрибуту, который я хочу, так как он продолжает сортировать их по имени человека:

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());
    }
}

Что я делаю не так?Я думал, что если я вызову «Collections.sort ()» для ArrayList объектов Student, он будет использовать метод «CompareTo ()» из моего класса Student, который использует атрибут «program».Я все еще учусь работать с этими методами, поэтому кое-что я не получаю.

Ответы [ 6 ]

0 голосов
/ 01 октября 2018

Я считаю, что если вы хотите отсортировать класс по определенному атрибуту, вам нужно использовать компаратор.

Попробуйте что-то вроде:

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);
}

Компаратор - это функция, которая существует вКоллекции, так что вам просто нужно вставить условие, которое вы ищете.

Дайте мне знать, если вы не можете выполнить его.

0 голосов
/ 01 октября 2018

Это хорошее время, чтобы напомнить о себе с книгой Effective Java . Пункт 40: Последовательно используйте Override.

Ваш базовый класс Person не использует @ Override примечание к методу compareTo , так что вы не получите никакой ошибки, если вы на самом деле не переопределите метод CompareTo, которым вы себя считаете.В этом случае тип параметра неправильный.Это должен быть Person, а не String.Метод не вызывается, и вместо него используется значение по умолчанию.

-me

0 голосов
/ 01 октября 2018

Ваш compareTo(String) метод в классе Person не имеет особого смысла, потому что он сравнивает this (Person) с String.В особенности это не вносит вклад в интерфейс Comparable<Person>, реализованный классом Person.

. Вы должны скорее сравнить this (a 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.Вы можете опустить этот метод, и при этом иметь тот же эффект.

0 голосов
/ 01 октября 2018

У вас есть два разных метода compareTo ().Тот, который вы ожидаете использовать, не вызывается Collections.sort ().

Если вы хотите делать заказы на учеников с использованием Collections.sort (), то вам нужен метод с сигнатурой compareTo (Student student);

Этот метод "перекрывается" с compareTo (Person person), и это проблема по двум причинам:

  • семантически, метод compareTo () на уровне Person устанавливает семантика и ваш метод compareTo () на уровне ученика отклоняется от этой семантики, и это никогда не является хорошей идеей.

  • технически, вы полагаетесьо деталях реализации, связанных с привязкой метода, чтобы заставить вашу систему вести себя как нужно.В лучшем случае это хитроумно.

Я бы искал метод сортировки, который использует явный предоставленный пользователем компаратор вместо метода сортировки, который опирается на внутренний compareTo ().

0 голосов
/ 01 октября 2018

Если вы хотите отсортировать объекты, используя различные порядки в соответствии с «естественным» порядком классов, вы должны использовать Arrays.sort(T[], Comparator<T>) с объектом Comparator, который реализует конкретный порядок сортировки или упорядочения.

javadoc для Comparable объясняет семантику, которую он должен реализовать.(Прочтите их внимательно!)

О естественном порядке:

  • "Естественный" порядок для Person[] будет определен методом compareTo(Person).
  • «Естественный» порядок для Student[] (или ArrayList<Student>) будет определяться методом compareTo(Student).
  • И так далее.
  • Ни в одном из этих случаев ваши compareTo(String) методы не будут использованы!
0 голосов
/ 01 октября 2018

Проблемы

  1. Вы не определили, как Person объекты должны сравниваться.
  2. Вы неправильно определили, как должны сравниваться экземпляры Student и Professor.
  3. Вы написали перегруженные методы compareTo(String), которые вводят в заблуждение.

Решения

  1. Правильно определите Person#compareTo, удалите его compareTo(String):

    public int compareTo(Person p) {
        return getName().compareTo(p.getName());
    }
    
  2. Определите 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 с (здесь, по программе студента) ".

  3. Я бы удалил эти методы.Не стоит иметь отдельный метод для простой строки кода, которая не соответствует области классов.

...