0Pricing
Java Academy · درس

واجهة Comparable

طبّق Comparable لمنح الفئة ترتيبًا طبيعيًا، واستخدمه مع Collections.sort

واجهة Comparable درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.

واجهة Comparable

تمنح Comparable<T> الفئةَ ترتيبًا طبيعيًا. طبّقها لجعل النُسخ قابلة للفرز باستخدام Collections.sort() وArrays.sort() والمجموعات المرتبة مثل TreeSet.

تطبيق Comparable

طبّق compareTo(T other) بحيث تُرجع قيمة سالبة عندما يكون هذا العنصر أصغر من other، وصفرًا عند التساوي، وقيمة موجبة عندما يكون أكبر منه.

class Product implements Comparable<Product> {
    private final String name;
    private final double price;

    Product(String name, double price) {
        this.name = name; this.price = price;
    }

    @Override
    public int compareTo(Product other) {
        return Double.compare(this.price, other.price); // ascending by price
    }

    @Override public String toString() { return name + "($" + price + ")"; }
}

List<Product> products = new ArrayList<>(List.of(
    new Product("Mouse", 29.99),
    new Product("Laptop", 999.0),
    new Product("Keyboard", 79.99)
));
Collections.sort(products);
System.out.println(products); // [Mouse($29.99), Keyboard($79.99), Laptop($999.0)]

عقد compareTo

يتطلب تطبيق Comparable بشكل صحيح استيفاء عقد:

  • التناظر المضاد: sgn(a.compareTo(b)) == -sgn(b.compareTo(a))
  • التعدي: إذا كان a > b وb > c، فيجب أن يكون a > c
  • الاتساق: إن a.compareTo(b) == 0 يعني أن a.equals(b) — ويُنصح بشدة بذلك

مقارنة القيم البدائية بأمان

لا تطرح القيم البدائية داخل compareTo مطلقًا، إذ يمكن أن يؤدي تجاوز سعة العدد الصحيح إلى نتائج خاطئة. استخدم Integer.compare() وDouble.compare() وغيرهما.

// WRONG: integer subtraction can overflow
int compareTo(Player other) {
    return this.score - other.score; // overflow if scores differ by > Integer.MAX_VALUE
}

// CORRECT: use Integer.compare
int compareTo(Player other) {
    return Integer.compare(this.score, other.score);
}

// For strings: delegate to String.compareTo
int compareTo(Player other) {
    return this.name.compareTo(other.name); // String handles it correctly
}

الترتيب الطبيعي في TreeSet

تحصل الفئات التي تطبّق Comparable تلقائيًا على موضع مناسب في المجموعات المرتبة مثل TreeSet وTreeMap.

class Priority implements Comparable<Priority> {
    enum Level { LOW, MEDIUM, HIGH, CRITICAL }
    final Level level;
    final String task;
    Priority(Level level, String task) { this.level = level; this.task = task; }
    @Override
    public int compareTo(Priority other) {
        return this.level.compareTo(other.level); // enum ordinal order
    }
    @Override public String toString() { return level + ": " + task; }
}

TreeSet<Priority> queue = new TreeSet<>();
queue.add(new Priority(Priority.Level.CRITICAL, "Fix prod crash"));
queue.add(new Priority(Priority.Level.LOW, "Update docs"));
queue.add(new Priority(Priority.Level.HIGH, "Deploy feature"));
queue.forEach(System.out::println);
// LOW: Update docs
// HIGH: Deploy feature
// CRITICAL: Fix prod crash

Comparable متعدد الحقول

للفرز وفق حقول متعددة، اربط المقارنات بالتسلسل: الحقل الأساسي، ثم الحقل الثانوي إذا تساوى الأساسي.

class Employee implements Comparable<Employee> {
    final String dept, name;
    final double salary;

    Employee(String dept, String name, double salary) {
        this.dept = dept; this.name = name; this.salary = salary;
    }

    @Override
    public int compareTo(Employee other) {
        int deptCmp = this.dept.compareTo(other.dept);
        if (deptCmp != 0) return deptCmp;           // primary: by dept
        return this.name.compareTo(other.name);      // secondary: by name
    }
}

اتساق Comparable وequals

يُنصح بشدة، وإن لم يكن ذلك مطلوبًا، بأن يتحقق a.compareTo(b) == 0 إذا وفقط إذا تحقق a.equals(b). ويؤدي انتهاك ذلك إلى أخطاء دقيقة في المجموعات والخرائط المرتبة.

// BigDecimal violates this: new BigDecimal("2.0").compareTo(new BigDecimal("2.00")) == 0
// but new BigDecimal("2.0").equals(new BigDecimal("2.00")) == false

// This causes TreeSet to treat them as equal (only one stored)
TreeSet<java.math.BigDecimal> set = new TreeSet<>();
set.add(new java.math.BigDecimal("2.0"));
set.add(new java.math.BigDecimal("2.00"));
System.out.println(set.size()); // 1 — compareTo-equal → same element

الفرز باستخدام Collections.sort

تستخدم Collections.sort() وArrays.sort() الترتيب الطبيعي الذي تحدده Comparable.

List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
Collections.sort(names); // natural alphabetical order
System.out.println(names); // [Alice, Bob, Charlie]

String[] arr = {"banana", "apple", "cherry"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // [apple, banana, cherry]

// Stream sorted() uses natural order
names.stream().sorted().forEach(System.out::println);

Comparable في البحث الثنائي

تتطلب Collections.binarySearch() أن تكون القائمة مرتبة وفق الترتيب الطبيعي، وأن تطبّق العناصر Comparable.

List<Integer> sorted = new ArrayList<>(List.of(1, 3, 5, 7, 9, 11));
int idx = Collections.binarySearch(sorted, 7);
System.out.println("Found 7 at index: " + idx); // 3

int missing = Collections.binarySearch(sorted, 4);
System.out.println("4 not found, insertion point: " + (-missing - 1)); // 2

Comparable مقابل Comparator

التمييز الأساسي:

  • Comparable: يحدد الترتيب الطبيعي الخاص بالفئة — ترتيب واحد لكل فئة
  • Comparator: يحدد ترتيبًا خارجيًا — عدد غير محدود من الترتيبات القابلة للتركيب

تطبيق عملي: لوحة المتصدرين

لوحة متصدرين تستخدم Comparable لترتيب طبيعي تنازلي حسب النقاط.

class LeaderboardEntry implements Comparable<LeaderboardEntry> {
    final String player;
    final int score;
    final long timestamp;

    LeaderboardEntry(String player, int score) {
        this.player = player; this.score = score;
        this.timestamp = System.nanoTime();
    }

    @Override
    public int compareTo(LeaderboardEntry other) {
        int scoreCmp = Integer.compare(other.score, this.score); // descending
        if (scoreCmp != 0) return scoreCmp;
        return Long.compare(this.timestamp, other.timestamp); // earlier = higher
    }

    @Override public String toString() { return player + ": " + score; }
}

TreeSet<LeaderboardEntry> board = new TreeSet<>();
board.add(new LeaderboardEntry("Alice", 950));
board.add(new LeaderboardEntry("Bob", 1200));
board.add(new LeaderboardEntry("Carol", 950));
board.forEach(System.out::println);
// Bob: 1200 / Alice: 950 / Carol: 950

تحقق سريع

ماذا تُرجع compareTo() عندما يكون العنصر الحالي أصغر من الوسيط؟

مراجعة: واجهة Comparable

أهم النقاط:

  • طبّق Comparable<T> لتحديد الترتيب الطبيعي للفئة
  • تُرجع compareTo قيمة سالبة عند الأصغر، وصفرًا عند التساوي، وقيمة موجبة عند الأكبر
  • استخدم Integer.compare()/Double.compare() — ولا تطرح القيم مطلقًا بسبب خطر تجاوز السعة
  • اربط المقارنات لفرز الحقول المتعددة: الأساسي ← الثانوي
  • يُستخدم الترتيب الطبيعي مع Collections.sort وArrays.sort وTreeSet وTreeMap
  • تحدد Comparable ترتيبًا واحدًا؛ استخدم Comparator للترتيبات المتعددة

الأسئلة الشائعة

هل درس «واجهة Comparable» مجاني؟

نعم — نص درس «واجهة Comparable» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.

ماذا ستتعلم في «واجهة Comparable»؟

طبّق Comparable لمنح الفئة ترتيبًا طبيعيًا، واستخدمه مع Collections.sort تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟

لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «واجهة Comparable»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟

نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. واجهة Comparable
  2. الفرز باستخدام Comparator وLambda
  3. الفرز متعدد المفاتيح باستخدام thenComparing
  4. فرز المصفوفات والمجموعات عمليًا
← العودة إلى Java Academy