Интерфейс компаратора, реализованный во вложенном классе

Я новичок на stackoverflow.com, но я часто использовал его для поиска ответов всякий раз, когда у меня возникала проблема, но теперь я не могу найти никаких результатов поиска по моей проблеме, поэтому я спрашиваю здесь :) Я учусь на Сертификация OCPJP SE 7, экзамен 1Z0-804, и я использую книгу (есть только одна доступная, на самом деле, книга Ганеша\Шармы). и интерфейс Comparable для сортировки массива элементов Student, но вопрос касается Comparator:

import java.util.*;

class Student implements Comparable<Student> {
    private String id, name;
    private Double cgpa;
    public String getName() {
        return name;
    }
    public String getId() {
        return id;
    }
    public Double getCgpa() {
        return cgpa;
    }
    public Student(String studentId, String studentName, double studentCGPA) {
        id=studentId;
        name=studentName;
        cgpa=studentCGPA;
    }
    public String toString() {
        return id+" "+name+" "+cgpa;
    }
    public int compareTo(Student that) {
        return this.id.compareTo(that.id);
    }
}

class StudentCGPA implements Comparator<Student> {
    public int compare(Student s1, Student s2) {
        return s1.getCgpa().compareTo(s2.getCgpa());
    }
}

class MyMainClass {
    public static void main(String[] args) {
        Student[] students =    {   new Student("cs011", "Lennon", 3.1),
                                    new Student("cs021", "McCartney", 3.4),
                                    new Student("cs012", "Harrison", 2.7),
                                    new Student("cs022", "Starr", 3.7),
                                };
        Arrays.sort(students, new StudentCGPA());
        System.out.println(Arrays.toString(students));
    }
}

Таким образом, он создает новый класс только для использования интерфейса Comparator с двумя объектами Student, но я думаю, что это очень неудобно, поэтому я задаюсь вопросом: почему я не могу использовать вложенный класс (внутри Student)? Нравится:

import java.util.*;

class Student implements Comparable<Student> {
    private String id, name;
    private Double cgpa;
    public String getName() {
        return name;
    }
    public String getId() {
        return id;
    }
    public Double getCgpa() {
        return cgpa;
    }
    public Student(String studentId, String studentName, double studentCGPA) {
        id=studentId;
        name=studentName;
        cgpa=studentCGPA;
    }
    public String toString() {
        return id+" "+name+" "+cgpa;
    }
    public int compareTo(Student that) {
        return this.id.compareTo(that.id);
    }
    static class StudentCGPA implements Comparator<Student> {
        public int compare(Student s1, Student s2) {
            return s1.getCgpa().compareTo(s2.getCgpa());
        }
    }
}

class MyMainClass {
    public static void main(String[] args) {
        Student[] students =    {   new Student("cs011", "Lennon", 3.1),
                                    new Student("cs021", "McCartney", 3.4),
                                    new Student("cs012", "Harrison", 2.7),
                                    new Student("cs022", "Starr", 3.7),
                                };
        Arrays.sort(students, new Student.StudentCGPA());
        System.out.println(Arrays.toString(students));
    }
}

В книге ничего не говорится об использовании вложенных классов вместо обычных, но я не понимаю, почему это должно быть плохо... Есть ли проблема с моим кодом (вторым)? Должен ли я следовать тому, что написано в книге, потому что моя реализация Comparator неверна? (Примечание: код компилируется и запускается без проблем, с ожидаемым результатом в обоих случаях)

[cs012 Harrison 2.7, cs011 Lennon 3.1, cs021 McCartney 3.4, cs022 Starr 3.7]

Пожалуйста, помогите: D Заранее спасибо.


person RaffoSorr    schedule 07.10.2014    source источник
comment
Несколько классов на единицу компиляции — это фактически устаревшая функция Java. Вы всегда должны отдавать предпочтение вложенным классам.   -  person Marko Topolnik    schedule 07.10.2014
comment
Если вы используете отдельный Comparator, рекомендуется поместить его исходный код в отдельный файл. Это не аргумент за или против вложенности класса Comparator. Весьма вероятно, что книга, из которой взят первоисточник, представляет его так, как это делается для удобства и ясности.   -  person John Bollinger    schedule 07.10.2014


Ответы (2)


Вы можете реализовать Comparator как статический вложенный класс сравниваемого класса, если вы управляете этим классом (и если это класс, а не интерфейс). Однако вовсе не редкость, когда вы хотите сравнить экземпляры класса, которым вы не управляете, в соответствии с порядком, который целевой класс изначально не поддерживает (либо будучи Comparable, либо предоставляя Comparator класс). В этом случае вы должны создать свой собственный отдельный файл Comparator.

Даже когда вы контролируете все, это в некоторой степени вопрос вкуса, следует ли реализовывать Comparators как классы верхнего уровня. Я не уверен, почему вы называете это «неудобным»; сам я обычно предпочитаю избегать вложенных классов, когда могу. Также обратите внимание, что вне зависимости от того, вложены вы или нет, класс реализации Comparator будет скомпилирован в отдельный файл класса.

person John Bollinger    schedule 07.10.2014
comment
Идеальный ответ, на который я надеялся! : DI не думал о конкретном случае, который вы объяснили, фактически, если бы я не мог получить доступ к классу, я бы не смог реализовать компаратор как вложенный класс, поэтому мне лучше всегда реализовывать его как отдельный класс :) Спасибо (и другим, конечно же) огромное! - person RaffoSorr; 07.10.2014

Нет реальной причины, по которой вам не следует реализовывать оба Comparable и Comparator.

class Student implements Comparable<Student>, Comparator<Student> {

    private final String id;
    private final String name;
    private final Double cgpa;

    public String getName() {
        return name;
    }

    public String getId() {
        return id;
    }

    public Double getCgpa() {
        return cgpa;
    }

    public Student(String studentId, String studentName, double studentCGPA) {
        id = studentId;
        name = studentName;
        cgpa = studentCGPA;
    }

    @Override
    public String toString() {
        return id + " " + name + " " + cgpa;
    }

    @Override
    public int compareTo(Student that) {
        return this.id.compareTo(that.id);
    }

    @Override
    public int compare(Student o1, Student o2) {
        return o1.getCgpa().compareTo(o2.getCgpa());
    }
}

Однако часто более целесообразно реализовать только Comparable и использовать другие методы (например, внутренние классы или анонимные классы) для выбора другого порядка.

    class ByCgpa implements Comparator<Student> {

        @Override
        public int compare(Student o1, Student o2) {
            return o1.getCgpa().compareTo(o2.getCgpa());
        }

    }

    Collections.sort(list, new ByCgpa());

static void sortByCgpaAndName(Collection<Student> students) {
    Collections.sort(students, new Comparator<Student> () {

        @Override
        public int compare(Student o1, Student o2) {
            int byCgpa = o1.getCgpa().compareTo(o2.getCgpa());
            return byCgpa != 0 ? byCgpa : o1.name.compareTo(o2.name);
        }
    });
}

См. здесь для дальнейшего обсуждения.

person OldCurmudgeon    schedule 07.10.2014
comment
@Serhiy - Какое отношение это имеет к вопросу об использовании вложенного класса для реализации Comparator? - person OldCurmudgeon; 07.10.2014
comment
Конечно, но вам может понадобиться упорядочить студентов по их имени в некоторых случаях и по их cgpa в других случаях, и когда вам нужны две или более разных реализации метода сравнения, вы не можете реализовать его в классе, который необходимо сравнить. , правильно? Но если мне нужны две разные реализации, я могу просто создать два вложенных класса, скажем, Student.StudentCGPA и Student.StudentName. - person RaffoSorr; 07.10.2014
comment
@OldCurmudgeon, может быть, мой вопрос не имеет отношения к его вопросу, но тогда ваш ответ тоже не имеет ничего общего с его вопросом ... потому что меня спросили: почему я не могу использовать вложенный класс (внутри Student)? А не почему бы мне не реализовать Comprataor и Comparable?... - person Serhiy; 07.10.2014
comment
@Serhiy для сравнения вам не нужно писать вложенный класс, верно? и иногда у вас есть только файл .class таких классов, как Student, исходный код которого вы не можете изменить, поэтому вы не можете написать вложенный класс, но да, если у вас есть код src, вы можете это сделать, но на практике вы используете campare () в первом случае (т.е. src недоступен) - person VijayD; 07.10.2014
comment
@Raffolox - Это правильно - внутренние классы и / или анонимные классы можно использовать для более тщательного контроля порядка ваших объектов. Я добавлю код для демонстрации. - person OldCurmudgeon; 07.10.2014
comment
@Viktor, честно говоря, я думаю, что пример просто плохой (тот, который опубликовал ОП), не уверен, что он такой же, как в книге. Очевидно, что я бы использовал Comparator только тогда, когда у меня нет доступа к коду, который я хотел бы сравнивать или когда требуется несколько сравнений для разных атрибутов. - person Serhiy; 07.10.2014
comment
@Serhiy, пример такой же, как в книге, проверьте страницу 189, если она у вас тоже есть ... - person RaffoSorr; 07.10.2014