Java オブジェクトの複数属性に基づく比較方法

JavaBeginner
オンラインで実践に進む

はじめに

Java オブジェクトを複数の属性に基づいて比較することは、Java 開発者にとって不可欠なスキルです。この機能により、アプリケーション内でのデータの効率的なソート、フィルタリング、および整理が可能になります。この実験(Lab)では、複数のプロパティを持つオブジェクトを処理するために、Java でさまざまな比較メカニズムを実装する方法を学びます。

equals() メソッドのオーバーライド、Comparable インターフェースの実装、および Comparator インターフェースの使用など、Java でオブジェクトを比較するための基本的なアプローチを探求します。実践的な例とハンズオン演習を通じて、各アプローチをいつ、どのように使用するかをしっかりと理解できるようになります。

複数の属性を持つ Student クラスの作成

この最初のステップでは、複数の属性を持つ学生を表すシンプルな Java クラスを作成します。これは、Java でのオブジェクト比較について学ぶための基盤となります。

プロジェクト構造の設定

まず、プロジェクト用のディレクトリを作成し、そこに移動します。

mkdir -p ~/project/java-comparison
cd ~/project/java-comparison

Student クラスの作成

次に、名前、年齢、成績などの複数の属性を持つ Student クラスを作成しましょう。WebIDE を開き、プロジェクトディレクトリに Student.java という名前の新しいファイルを作成し、次の内容を記述します。

public class Student {
    private String name;
    private int age;
    private double grade;

    // Constructor
    public Student(String name, int age, double grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }

    // Getters
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public double getGrade() {
        return grade;
    }

    // toString method for easy display
    @Override
    public String toString() {
        return "Student{name='" + name + "', age=" + age + ", grade=" + grade + "}";
    }
}

このクラスは、name (String)、age (整数)、および grade (double) の 3 つの属性を持つ学生を表します。また、コンストラクタ、各属性のゲッター、および学生情報を簡単に表示するための toString() メソッドも含まれています。

Student クラスのテスト

Student クラスをテストするためのメインクラスを作成しましょう。StudentTest.java という名前の新しいファイルを作成し、次の内容を記述します。

public class StudentTest {
    public static void main(String[] args) {
        // Create some student objects
        Student alice = new Student("Alice", 20, 85.5);
        Student bob = new Student("Bob", 22, 90.0);
        Student charlie = new Student("Charlie", 19, 78.3);

        // Display student information
        System.out.println("Student 1: " + alice);
        System.out.println("Student 2: " + bob);
        System.out.println("Student 3: " + charlie);

        // Compare two students using == (identity comparison)
        Student aliceCopy = alice;
        System.out.println("\nIdentity comparison (==):");
        System.out.println("alice == bob: " + (alice == bob));
        System.out.println("alice == aliceCopy: " + (alice == aliceCopy));

        // Try to compare students with built-in methods
        System.out.println("\nNote: At this point, we cannot properly compare students based on their attributes.");
        System.out.println("We will implement proper comparison in the next steps.");
    }
}

コンパイルと実行

それでは、コードをコンパイルして実行しましょう。

javac StudentTest.java
java StudentTest

次のような出力が表示されるはずです。

Student 1: Student{name='Alice', age=20, grade=85.5}
Student 2: Student{name='Bob', age=22, grade=90.0}
Student 3: Student{name='Charlie', age=19, grade=78.3}

Identity comparison (==):
alice == bob: false
alice == aliceCopy: true

Note: At this point, we cannot properly compare students based on their attributes.
We will implement proper comparison in the next steps.

オブジェクト比較の基本を理解する

テストでは、2 つの Student オブジェクトを比較するために == 演算子を使用したことに注意してください。これは Java では identity comparison と呼ばれ、2 つの参照がメモリ内の同じオブジェクトを指しているかどうかをチェックします。

しかし、多くの場合、コンテンツまたは属性に基づいてオブジェクトを比較する必要があります。これは equality comparison と呼ばれます。Java には、この目的のためにいくつかのメカニズムが用意されています。

  1. equals() メソッドのオーバーライド
  2. Comparable インターフェースの実装
  3. Comparator インターフェースの使用

次のステップでは、これらのメカニズムを実装して、属性に基づいて Student オブジェクトを比較します。

equals() および hashCode() メソッドの実装

Comparable および Comparator インターフェースに入る前に、まず Student クラスで equals() および hashCode() メソッドを実装しましょう。これらのメソッドは、Java での適切なオブジェクト比較の基本です。

equals() と hashCode() の理解

Java では、equals() メソッドは、2 つのオブジェクトがその内容に基づいて等しいかどうかをチェックするために使用され、hashCode() メソッドは、オブジェクトを表す数値値を生成します。これらの 2 つのメソッドは、特にオブジェクトが HashMapHashSet などのコレクションに格納されている場合に連携して機能します。

適切な実装は、次のルールに従う必要があります。

  • 2 つのオブジェクトが equals() に従って等しい場合、それらは同じハッシュコードを持っている必要があります。
  • 2 つのオブジェクトが同じハッシュコードを持っている場合、必ずしも等しいとは限りません。

Student クラスの更新

これらのメソッドをオーバーライドするために、Student クラスを更新しましょう。Student.java を開き、次のメソッドを追加します。

public class Student {
    private String name;
    private int age;
    private double grade;

    // Existing constructor and getters...

    // Existing toString method...

    // Override equals method
    @Override
    public boolean equals(Object obj) {
        // Check if same object reference
        if (this == obj) return true;
        // Check if null or different class
        if (obj == null || getClass() != obj.getClass()) return false;

        // Cast to Student
        Student other = (Student) obj;

        // Compare attributes
        return age == other.age &&
               Double.compare(grade, other.grade) == 0 &&
               (name == null ? other.name == null : name.equals(other.name));
    }

    // Override hashCode method
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        result = 31 * result + (int) (Double.doubleToLongBits(grade) ^ (Double.doubleToLongBits(grade) >>> 32));
        return result;
    }
}

equals() メソッドは、標準的なパターンに従います。

  1. オブジェクトがそれ自体と比較されているかどうかを確認します
  2. オブジェクトが null であるか、異なるクラスであるかどうかを確認します
  3. オブジェクトを適切な型にキャストします
  4. 各属性を等価性について比較します

hashCode() メソッドは、すべての属性のハッシュコードを組み合わせて、オブジェクトの一意のハッシュコードを生成します。

equals() と hashCode() のテスト

次に、これらのメソッドをテストするために、StudentTest.java ファイルを更新しましょう。

public class StudentTest {
    public static void main(String[] args) {
        // Create some student objects
        Student alice = new Student("Alice", 20, 85.5);
        Student bob = new Student("Bob", 22, 90.0);
        Student aliceDuplicate = new Student("Alice", 20, 85.5); // Same attributes as Alice

        // Display student information
        System.out.println("Student 1: " + alice);
        System.out.println("Student 2: " + bob);
        System.out.println("Student 3 (Alice duplicate): " + aliceDuplicate);

        // Identity comparison (==)
        System.out.println("\nIdentity comparison (==):");
        System.out.println("alice == bob: " + (alice == bob));
        System.out.println("alice == aliceDuplicate: " + (alice == aliceDuplicate));

        // Equality comparison (equals())
        System.out.println("\nEquality comparison (equals()):");
        System.out.println("alice.equals(bob): " + alice.equals(bob));
        System.out.println("alice.equals(aliceDuplicate): " + alice.equals(aliceDuplicate));

        // Hash code comparison
        System.out.println("\nHash code comparison:");
        System.out.println("alice.hashCode(): " + alice.hashCode());
        System.out.println("bob.hashCode(): " + bob.hashCode());
        System.out.println("aliceDuplicate.hashCode(): " + aliceDuplicate.hashCode());
    }
}

コンパイルと実行

更新されたコードをコンパイルして実行しましょう。

javac Student.java StudentTest.java
java StudentTest

出力は次のようになります。

Student 1: Student{name='Alice', age=20, grade=85.5}
Student 2: Student{name='Bob', age=22, grade=90.0}
Student 3 (Alice duplicate): Student{name='Alice', age=20, grade=85.5}

Identity comparison (==):
alice == bob: false
alice == aliceDuplicate: false

Equality comparison (equals()):
alice.equals(bob): false
alice.equals(aliceDuplicate): true

Hash code comparison:
alice.hashCode(): 62509338
bob.hashCode(): 62565066
aliceDuplicate.hashCode(): 62509338

alicealiceDuplicate は異なるオブジェクトですが (== 比較で示されているように)、属性値が同じであるため、equals() メソッドに従って等しいと見なされることに注意してください。また、equals()hashCode() の間の契約で要求されているように、同じハッシュコードを持っています。

equals() は、2 つのオブジェクトが等しいかどうかを判断するのに役立ちますが、オブジェクト間の順序 (ソートされたリストでどちらが最初に来るかなど) を確立するのには役立ちません。そのためには、次のステップで実装する Comparable インターフェースが必要です。

Comparable インターフェースの実装

equals() メソッドを使用すると、2 つのオブジェクトが等しいかどうかをチェックできますが、順序を確立するのには役立ちません。そのため、Java には Comparable インターフェースが用意されており、オブジェクトの「自然な順序」を定義できます。

Comparable インターフェースの理解

Comparable<T> インターフェースには、単一のメソッド compareTo(T o) があり、現在のオブジェクトを同じ型の別のオブジェクトと比較します。このメソッドは、次を返します。

  • 現在のオブジェクトが他のオブジェクトより小さい場合は負の整数
  • 現在のオブジェクトが他のオブジェクトと等しい場合はゼロ
  • 現在のオブジェクトが他のオブジェクトより大きい場合は正の整数

このインターフェースを実装することにより、クラスのオブジェクトをどのように並べ替えるかを定義できます。

Student クラスの更新

Student クラスを更新して、Comparable インターフェースを実装しましょう。学生の成績 (成績が高いほど先に来る)、次に年齢 (若い学生が先に来る)、最後に名前 (アルファベット順) に基づいて自然な順序を定義します。

Student.java ファイルを更新します。

public class Student implements Comparable<Student> {
    private String name;
    private int age;
    private double grade;

    // Existing constructor, getters, toString, equals, and hashCode methods...

    // Implement compareTo method from Comparable interface
    @Override
    public int compareTo(Student other) {
        // Compare by grade (descending order)
        if (Double.compare(other.grade, this.grade) != 0) {
            return Double.compare(other.grade, this.grade);
        }

        // If grades are equal, compare by age (ascending order)
        if (this.age != other.age) {
            return Integer.compare(this.age, other.age);
        }

        // If grades and ages are equal, compare by name (alphabetical order)
        return this.name.compareTo(other.name);
    }
}

Comparable 実装のテストの作成

Comparable の実装をテストするために、新しいファイル ComparableTest.java を作成しましょう。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ComparableTest {
    public static void main(String[] args) {
        // Create a list of students
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 20, 85.5));
        students.add(new Student("Bob", 22, 90.0));
        students.add(new Student("Charlie", 19, 78.3));
        students.add(new Student("David", 21, 85.5));
        students.add(new Student("Eve", 20, 92.7));

        // Display unsorted list
        System.out.println("Unsorted list of students:");
        for (Student student : students) {
            System.out.println(student);
        }

        // Sort the list using the natural ordering defined by Comparable
        Collections.sort(students);

        // Display sorted list
        System.out.println("\nSorted list of students (by grade descending, then age ascending, then name):");
        for (Student student : students) {
            System.out.println(student);
        }

        // Let's compare some students directly using compareTo
        Student alice = students.get(3); // Alice should be at index 3 after sorting
        Student bob = students.get(1);   // Bob should be at index 1 after sorting

        System.out.println("\nComparing students directly using compareTo:");
        int comparison = alice.compareTo(bob);
        System.out.println("alice.compareTo(bob) = " + comparison);

        if (comparison < 0) {
            System.out.println("Alice comes before Bob in the natural ordering");
        } else if (comparison > 0) {
            System.out.println("Bob comes before Alice in the natural ordering");
        } else {
            System.out.println("Alice and Bob are equal in the natural ordering");
        }
    }
}

コンパイルと実行

コードをコンパイルして実行しましょう。

javac Student.java ComparableTest.java
java ComparableTest

出力は次のようになります。

Unsorted list of students:
Student{name='Alice', age=20, grade=85.5}
Student{name='Bob', age=22, grade=90.0}
Student{name='Charlie', age=19, grade=78.3}
Student{name='David', age=21, grade=85.5}
Student{name='Eve', age=20, grade=92.7}

Sorted list of students (by grade descending, then age ascending, then name):
Student{name='Eve', age=20, grade=92.7}
Student{name='Bob', age=22, grade=90.0}
Student{name='Alice', age=20, grade=85.5}
Student{name='David', age=21, grade=85.5}
Student{name='Charlie', age=19, grade=78.3}

Comparing students directly using compareTo:
alice.compareTo(bob) = 1
Bob comes before Alice in the natural ordering

学生が成績の高い順に並べ替えられていることに注意してください。成績が同じ場合 (Alice と David のように、どちらも 85.5 の場合)、年齢の若い順に並べ替えられます。

Comparable インターフェースは、オブジェクトの自然な順序を提供しますが、さまざまな方法でオブジェクトを並べ替えたい場合はどうでしょうか?たとえば、学生を名前で並べ替えたり、年齢で並べ替えたりしたい場合があります。そこで、Comparator インターフェースが登場します。これは、次のステップで説明します。

カスタム順序付けのための Comparator の使用

Comparable インターフェースはクラスの自然な順序を提供しますが、場合によっては、さまざまな基準に基づいてオブジェクトを異なる方法で並べ替える必要があります。ここで、Comparator インターフェースが役立ちます。

Comparator インターフェースの理解

Comparator<T> インターフェースは、同じ型の 2 つのオブジェクトを比較するメソッド compare(T o1, T o2) を定義します。比較されるクラスによって実装される Comparable とは異なり、Comparator は、さまざまな順序付け基準を定義できる別のクラスまたはラムダ式です。

カスタム Comparator の作成

Student クラスのいくつかの Comparator を作成しましょう。

  1. NameComparator: 学生を名前で並べ替えます (アルファベット順)
  2. AgeComparator: 学生を年齢で並べ替えます (昇順)
  3. GradeComparator: 学生を成績で並べ替えます (降順)

次の内容で、StudentComparators.java という新しいファイルを作成します。

import java.util.Comparator;

public class StudentComparators {
    // Comparator for sorting students by name
    public static class NameComparator implements Comparator<Student> {
        @Override
        public int compare(Student s1, Student s2) {
            return s1.getName().compareTo(s2.getName());
        }
    }

    // Comparator for sorting students by age
    public static class AgeComparator implements Comparator<Student> {
        @Override
        public int compare(Student s1, Student s2) {
            return Integer.compare(s1.getAge(), s2.getAge());
        }
    }

    // Comparator for sorting students by grade (descending)
    public static class GradeComparator implements Comparator<Student> {
        @Override
        public int compare(Student s1, Student s2) {
            return Double.compare(s2.getGrade(), s1.getGrade());
        }
    }

    // Multi-attribute comparator: sort by grade (descending), then by name (alphabetically)
    public static class GradeNameComparator implements Comparator<Student> {
        @Override
        public int compare(Student s1, Student s2) {
            // First compare by grade (descending)
            int gradeComparison = Double.compare(s2.getGrade(), s1.getGrade());
            if (gradeComparison != 0) {
                return gradeComparison;
            }

            // If grades are equal, compare by name (alphabetically)
            return s1.getName().compareTo(s2.getName());
        }
    }
}

Comparator のテスト

次に、これらの Comparator を使用する方法を示すテストクラスを作成しましょう。ComparatorTest.java という名前のファイルを作成します。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Comparator;

public class ComparatorTest {
    public static void main(String[] args) {
        // Create a list of students
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 20, 85.5));
        students.add(new Student("Bob", 22, 90.0));
        students.add(new Student("Charlie", 19, 78.3));
        students.add(new Student("David", 21, 85.5));
        students.add(new Student("Eve", 20, 92.7));

        // Display original list
        System.out.println("Original list of students:");
        printStudents(students);

        // Sort by name using NameComparator
        Collections.sort(students, new StudentComparators.NameComparator());
        System.out.println("\nStudents sorted by name:");
        printStudents(students);

        // Sort by age using AgeComparator
        Collections.sort(students, new StudentComparators.AgeComparator());
        System.out.println("\nStudents sorted by age (ascending):");
        printStudents(students);

        // Sort by grade using GradeComparator
        Collections.sort(students, new StudentComparators.GradeComparator());
        System.out.println("\nStudents sorted by grade (descending):");
        printStudents(students);

        // Sort by grade, then by name using GradeNameComparator
        Collections.sort(students, new StudentComparators.GradeNameComparator());
        System.out.println("\nStudents sorted by grade (descending), then by name:");
        printStudents(students);

        // Using Java 8 lambda expressions for comparators
        System.out.println("\nUsing Java 8 lambda expressions:");

        // Sort by name (alphabetically) using lambda
        Collections.sort(students, (s1, s2) -> s1.getName().compareTo(s2.getName()));
        System.out.println("\nStudents sorted by name (using lambda):");
        printStudents(students);

        // Sort by age (descending) using lambda
        Collections.sort(students, (s1, s2) -> Integer.compare(s2.getAge(), s1.getAge()));
        System.out.println("\nStudents sorted by age (descending, using lambda):");
        printStudents(students);

        // Using Comparator.comparing method
        System.out.println("\nUsing Comparator.comparing method:");

        // Sort by name
        Collections.sort(students, Comparator.comparing(Student::getName));
        System.out.println("\nStudents sorted by name (using Comparator.comparing):");
        printStudents(students);

        // Sort by grade (descending), then by age (ascending), then by name
        Collections.sort(students,
            Comparator.comparing(Student::getGrade, Comparator.reverseOrder())
                      .thenComparing(Student::getAge)
                      .thenComparing(Student::getName));
        System.out.println("\nStudents sorted by grade (desc), then age (asc), then name:");
        printStudents(students);
    }

    // Helper method to print the list of students
    private static void printStudents(List<Student> students) {
        for (Student student : students) {
            System.out.println(student);
        }
    }
}

コンパイルと実行

コードをコンパイルして実行しましょう。

javac Student.java StudentComparators.java ComparatorTest.java
java ComparatorTest

出力は、さまざまな Comparator が学生の並べ替え順序にどのように影響するかを示します。

Original list of students:
Student{name='Alice', age=20, grade=85.5}
Student{name='Bob', age=22, grade=90.0}
Student{name='Charlie', age=19, grade=78.3}
Student{name='David', age=21, grade=85.5}
Student{name='Eve', age=20, grade=92.7}

Students sorted by name:
Student{name='Alice', age=20, grade=85.5}
Student{name='Bob', age=22, grade=90.0}
Student{name='Charlie', age=19, grade=78.3}
Student{name='David', age=21, grade=85.5}
Student{name='Eve', age=20, grade=92.7}

... (and so on for the other sorting methods)

Comparable と Comparator の主な違い

ComparableComparator の違いを理解することが重要です。

  1. 実装場所:

    • Comparable はクラス自体によって実装されます。
    • Comparator は、別のクラスまたはラムダ式で実装されます。
  2. 順序付けの数:

    • Comparable は、クラスの単一の「自然な順序」を定義します。
    • Comparator は、複数の異なる順序付けを許可します。
  3. メソッドシグネチャ:

    • Comparable には int compareTo(T o) があります
    • Comparator には int compare(T o1, T o2) があります
  4. 使用法:

    • 明らかな自然な順序がある場合、Comparable はより簡単です。
    • 複数の順序付けが必要な場合、Comparator はより柔軟です。

最後のステップでは、ComparableComparator の両方を使用して学生データベースを管理する、実際のアプリケーションを作成します。

学生管理システムの構築

equals()Comparable、および Comparator を使用してオブジェクトを比較する方法を理解したので、すべてを実用的なアプリケーションにまとめたシンプルな学生管理システムを構築しましょう。

StudentManager クラスの作成

学生のコレクションを管理し、それらに対してさまざまな操作を提供するクラスを作成しましょう。StudentManager.java という名前のファイルを作成します。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

public class StudentManager {
    private List<Student> students;

    public StudentManager() {
        students = new ArrayList<>();
    }

    // Add a student to the list
    public void addStudent(Student student) {
        students.add(student);
    }

    // Get all students
    public List<Student> getAllStudents() {
        return new ArrayList<>(students); // Return a copy to prevent modification
    }

    // Get top students by grade
    public List<Student> getTopStudents(int count) {
        List<Student> sortedStudents = new ArrayList<>(students);
        Collections.sort(sortedStudents, new StudentComparators.GradeComparator());

        // Return the top 'count' students or all if there are fewer
        return sortedStudents.subList(0, Math.min(count, sortedStudents.size()));
    }

    // Get students sorted by name
    public List<Student> getStudentsSortedByName() {
        List<Student> sortedStudents = new ArrayList<>(students);
        Collections.sort(sortedStudents, new StudentComparators.NameComparator());
        return sortedStudents;
    }

    // Get students sorted by age
    public List<Student> getStudentsSortedByAge() {
        List<Student> sortedStudents = new ArrayList<>(students);
        Collections.sort(sortedStudents, new StudentComparators.AgeComparator());
        return sortedStudents;
    }

    // Get students with grade above threshold
    public List<Student> getStudentsAboveGrade(double threshold) {
        List<Student> result = new ArrayList<>();
        for (Student student : students) {
            if (student.getGrade() > threshold) {
                result.add(student);
            }
        }
        return result;
    }

    // Get students grouped by age
    public Map<Integer, List<Student>> getStudentsGroupedByAge() {
        Map<Integer, List<Student>> map = new HashMap<>();

        for (Student student : students) {
            int age = student.getAge();
            if (!map.containsKey(age)) {
                map.put(age, new ArrayList<>());
            }
            map.get(age).add(student);
        }

        return map;
    }

    // Find a student by name (returns null if not found)
    public Student findStudentByName(String name) {
        for (Student student : students) {
            if (student.getName().equals(name)) {
                return student;
            }
        }
        return null;
    }

    // Get student count
    public int getStudentCount() {
        return students.size();
    }
}

メインアプリケーションの作成

次に、StudentManager クラスを使用するメインアプリケーションを作成しましょう。StudentManagementApp.java という名前のファイルを作成します。

import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class StudentManagementApp {
    private static StudentManager manager = new StudentManager();
    private static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        // Add some sample students
        initializeData();

        boolean running = true;
        while (running) {
            displayMenu();
            int choice = getIntInput("Enter your choice: ");

            switch (choice) {
                case 1:
                    addStudent();
                    break;
                case 2:
                    displayAllStudents();
                    break;
                case 3:
                    displayTopStudents();
                    break;
                case 4:
                    displayStudentsSortedByName();
                    break;
                case 5:
                    displayStudentsSortedByAge();
                    break;
                case 6:
                    displayStudentsAboveGrade();
                    break;
                case 7:
                    displayStudentsGroupedByAge();
                    break;
                case 8:
                    findStudent();
                    break;
                case 9:
                    running = false;
                    break;
                default:
                    System.out.println("Invalid choice. Please try again.");
            }

            System.out.println(); // Empty line for better readability
        }

        System.out.println("Thank you for using the Student Management System.");
        scanner.close();
    }

    private static void displayMenu() {
        System.out.println("===== Student Management System =====");
        System.out.println("1. Add a new student");
        System.out.println("2. Display all students");
        System.out.println("3. Display top students by grade");
        System.out.println("4. Display students sorted by name");
        System.out.println("5. Display students sorted by age");
        System.out.println("6. Display students above a grade threshold");
        System.out.println("7. Display students grouped by age");
        System.out.println("8. Find a student by name");
        System.out.println("9. Exit");
    }

    private static void initializeData() {
        manager.addStudent(new Student("Alice", 20, 85.5));
        manager.addStudent(new Student("Bob", 22, 90.0));
        manager.addStudent(new Student("Charlie", 19, 78.3));
        manager.addStudent(new Student("David", 21, 85.5));
        manager.addStudent(new Student("Eve", 20, 92.7));
    }

    private static void addStudent() {
        System.out.println("=== Add a new student ===");
        String name = getStringInput("Enter student name: ");
        int age = getIntInput("Enter student age: ");
        double grade = getDoubleInput("Enter student grade: ");

        manager.addStudent(new Student(name, age, grade));
        System.out.println("Student added successfully.");
    }

    private static void displayAllStudents() {
        System.out.println("=== All Students ===");
        List<Student> students = manager.getAllStudents();
        displayStudents(students);
    }

    private static void displayTopStudents() {
        int count = getIntInput("Enter the number of top students to display: ");
        System.out.println("=== Top " + count + " Students ===");
        List<Student> topStudents = manager.getTopStudents(count);
        displayStudents(topStudents);
    }

    private static void displayStudentsSortedByName() {
        System.out.println("=== Students Sorted by Name ===");
        List<Student> sortedStudents = manager.getStudentsSortedByName();
        displayStudents(sortedStudents);
    }

    private static void displayStudentsSortedByAge() {
        System.out.println("=== Students Sorted by Age ===");
        List<Student> sortedStudents = manager.getStudentsSortedByAge();
        displayStudents(sortedStudents);
    }

    private static void displayStudentsAboveGrade() {
        double threshold = getDoubleInput("Enter the grade threshold: ");
        System.out.println("=== Students Above Grade " + threshold + " ===");
        List<Student> filteredStudents = manager.getStudentsAboveGrade(threshold);
        displayStudents(filteredStudents);
    }

    private static void displayStudentsGroupedByAge() {
        System.out.println("=== Students Grouped by Age ===");
        Map<Integer, List<Student>> groupedStudents = manager.getStudentsGroupedByAge();

        for (Map.Entry<Integer, List<Student>> entry : groupedStudents.entrySet()) {
            System.out.println("Age " + entry.getKey() + ":");
            displayStudents(entry.getValue());
            System.out.println();
        }
    }

    private static void findStudent() {
        String name = getStringInput("Enter the name of the student to find: ");
        Student student = manager.findStudentByName(name);

        if (student != null) {
            System.out.println("=== Student Found ===");
            System.out.println(student);
        } else {
            System.out.println("Student with name '" + name + "' not found.");
        }
    }

    private static void displayStudents(List<Student> students) {
        if (students.isEmpty()) {
            System.out.println("No students to display.");
            return;
        }

        for (Student student : students) {
            System.out.println(student);
        }
    }

    private static String getStringInput(String prompt) {
        System.out.print(prompt);
        return scanner.nextLine();
    }

    private static int getIntInput(String prompt) {
        while (true) {
            try {
                System.out.print(prompt);
                String input = scanner.nextLine();
                return Integer.parseInt(input);
            } catch (NumberFormatException e) {
                System.out.println("Invalid input. Please enter a valid integer.");
            }
        }
    }

    private static double getDoubleInput(String prompt) {
        while (true) {
            try {
                System.out.print(prompt);
                String input = scanner.nextLine();
                return Double.parseDouble(input);
            } catch (NumberFormatException e) {
                System.out.println("Invalid input. Please enter a valid number.");
            }
        }
    }
}

アプリケーションのコンパイルと実行

学生管理システムをコンパイルして実行しましょう。

javac Student.java StudentComparators.java StudentManager.java StudentManagementApp.java
java StudentManagementApp

これで、次のことができるインタラクティブメニューが表示されます。

  1. 新しい学生を追加する
  2. すべての学生を表示する
  3. 成績で上位の学生を表示する
  4. 名前で並べ替えられた学生を表示する
  5. 年齢で並べ替えられた学生を表示する
  6. 成績のしきい値を超える学生を表示する
  7. 年齢別にグループ化された学生を表示する
  8. 名前で学生を検索する
  9. アプリケーションを終了する

さまざまなオプションを試して、実装したさまざまな比較メカニズムが実際のアプリケーションでどのように機能するかを確認してください。たとえば、

  • オプション 3 は、GradeComparator を使用して、成績で上位の学生を見つけます
  • オプション 4 は、NameComparator を使用して、学生を名前で並べ替えます
  • オプション 5 は、AgeComparator を使用して、学生を年齢で並べ替えます

この学生管理システムは、学習した比較メカニズムを実際のシナリオに適用して、データを効果的に管理および整理する方法を示しています。

主なポイント

この実験を通して、次のことを学びました。

  1. 複数の属性を持つ Java クラスを作成する方法
  2. 正しいオブジェクト比較のために equals()hashCode() をオーバーライドする方法
  3. 自然な順序を定義するために Comparable インターフェースを実装する方法
  4. カスタム順序付けに Comparator インターフェースを使用する方法
  5. これらの概念を実用的なアプリケーションに適用する方法

これらのスキルは、Java 開発者にとって不可欠であり、データ処理からユーザーインターフェイスまで、幅広いアプリケーションで役立ちます。

まとめ

この実験では、複数の属性に基づいて Java オブジェクトを比較する方法を学びました。Java でのオブジェクト比較のための 3 つの主要なメカニズムを調べました。

  1. equals() メソッドと hashCode() メソッドのオーバーライド: これらのメソッドを適切に実装して、2 つのオブジェクトがその内容に基づいて等しいかどうかを確認する方法を学びました。

  2. Comparable インターフェースの実装: compareTo() メソッドを実装することにより、オブジェクトの自然な順序を定義する方法を発見しました。これにより、複数の属性に基づいてオブジェクトを並べ替えることができます。

  3. Comparator インターフェースの使用: さまざまな基準に基づいて、さまざまな方法でオブジェクトを並べ替えるカスタム Comparator を作成する方法を調べました。

これらの概念を適用して、これらの比較メカニズムが実際のアプリケーションでどのように連携するかを示す、実用的な学生管理システムを構築しました。

これらのスキルは、効果的な Java プログラミング、特に並べ替え、フィルタリング、または比較する必要があるオブジェクトのコレクションを扱う場合に不可欠です。オブジェクト比較を理解することで、より効率的で堅牢なアプリケーションを構築できます。

Java 開発者としての道のりにおいて、これらのテクニックを練習し続けてください。それらは非常に貴重なものとなるでしょう。