2014-10-07 3 views
3

Я новичок в stackoverflow.com, но я часто использовал его для поиска ответов, когда у меня была проблема, но теперь я не могу найти результат поиска моей проблемы, поэтому я спрашивая здесь :) Я изучаю сертификацию OCPJP SE 7, экзамен 1Z0-804, и я использую книгу (есть только один доступный afaik, Ganesh \ Sharma's) В главе коллекций о компараторе интерфейс, книга обеспечить этот пример использования как компаратора и Сопоставимый интерфейса для сортировки массива студенческих элементов, но вопрос о компараторе:Интерфейс компаратора реализован во вложенном классе

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

Так он создает новый класс только для USI ng интерфейс 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)); 
    } 
} 

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

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

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

+0

Несколько классов на единицу компиляции являются фактически непринужденной функцией Java. Вы всегда должны предпочесть вложенные классы. –

+0

Если вы используете отдельный «Comparator», тогда хорошая практика - поместить его источник в отдельный файл. Это не аргумент за или против вложенности класса 'Comparator'. Очень вероятно, что ** книга **, из которой вырисовывается исходный источник, представляет ее так же, как и для удобства и ясности. –

ответ

4

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

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

+1

Идеальный ответ, на который я надеялся! : DI не думал о конкретном случае, который вы объяснили, эффективно, если бы я не мог получить доступ к классу, я бы не смог реализовать Компаратор в качестве вложенного класса, поэтому лучше его реализовать как отдельный класс :) Спасибо (и другим тоже, конечно) много! – Raffolox

-2

Нет никакой реальной причины, по которой вы не должны фактически реализовывать и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); 
     } 
    }); 
} 

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

+0

И пункт реализации обоих? Я думаю, вы немного пропустили то, что было задано. – Serhiy

+0

@Serhiy - Как это относится к вопросу об использовании вложенного класса для реализации «Comparator»? – OldCurmudgeon

+0

Уверен, но вам может потребоваться заказать студентов по их имени в некоторых случаях и по их cgpa в других случаях, и когда вам понадобятся две или несколько различных реализаций метода сравнения, вы не сможете реализовать его в классе, который должен быть по сравнению, правильно? Но если мне нужно две разные реализации, я могу просто создать два вложенных класса, скажем, Student.StudentCGPA и Student.StudentName – Raffolox