0Pricing
Java Academy · درس

Wildcards ذات الحد السفلي

? super T للمستهلِكات

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

محرف البدل ذو الحد السفلي

? super T هو محرف بدل ذي حد سفلي. ويعني "نوعًا غير معروف يكون T أو نوعًا فائقًا لـ T".

يمكن أن يشير List<? super Integer> إلى List<Integer> أو List<Number> أو List<Object>.

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

public class Main {
    public static void main(String[] args) {
        List<? super Integer> a = new ArrayList<Number>();
        List<? super Integer> b = new ArrayList<Object>();
        a.add(1);
        b.add(2);
        System.out.println(a + " " + b);
    }
}

الكتابة إلى مستهلِك

باستخدام ? super Integer، يمكنك بأمان إضافة أي Integer (أو نوع فرعي من Integer).

أيًا كان نوع القائمة الحقيقي، فهي على الأقل قائمة من نوع فائق لـ Integer، ولذلك يلائمها Integer دائمًا.

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

public class Main {
    static void addNumbers(List<? super Integer> dest) {
        for (int i = 1; i <= 3; i++) dest.add(i);
    }
    public static void main(String[] args) {
        List<Number> nums = new ArrayList<>();
        addNumbers(nums);
        System.out.println(nums);
    }
}

تمنحك القراءة القيمة Object

المقابل هو أنه عند القراءة من قائمة من النوع ? super T، لا يعرف المصرّف سوى أن العناصر من نوع فائق غير معروف لـ T.

النوع الآمن الوحيد للقراءة هو Object.

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

public class Main {
    public static void main(String[] args) {
        List<? super Integer> list = new ArrayList<Number>();
        list.add(10);
        Object o = list.get(0); // only Object is guaranteed
        // Integer i = list.get(0); // would NOT compile
        System.out.println(o);
    }
}

لماذا القراءة محدودة

قد تكون List<? super Integer> في الواقع من النوع List<Object> وتحتوي على سلاسل نصية.

لذلك قد تُرجع القراءة أي Object. لا يستطيع المصرّف ضمان أن القيمة Integer، ومن ثم لا تعطي القراءة سوى Object.

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

public class Main {
    public static void main(String[] args) {
        List<Object> raw = new ArrayList<>();
        raw.add("a string");
        List<? super Integer> view = raw; // legal: Object is a supertype of Integer
        view.add(5);
        System.out.println(view.get(0).getClass().getSimpleName());
    }
}

حالة استخدام المستهلِك

استخدم ? super T عندما تكون الطريقة تستهلك القيم فقط، أي تكتبها في المجموعة.

الطريقة التي تملأ مجموعة وجهة هي الحالة التقليدية لذلك.

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

public class Main {
    static void fill(List<? super String> dest, int count) {
        for (int i = 0; i < count; i++) dest.add("item" + i);
    }
    public static void main(String[] args) {
        List<Object> objs = new ArrayList<>();
        fill(objs, 3);
        System.out.println(objs);
    }
}

تعمل إضافة الأنواع الفرعية أيضًا

باستخدام ? super Number، يمكنك إضافة أي Number أو أي نوع فرعي منه: Integer أو Double أو Long.

يضمن الحد السفلي أن القائمة تقبل Number على الأقل، ولذلك تلائمها جميع الأنواع الفرعية.

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

public class Main {
    public static void main(String[] args) {
        List<? super Number> list = new ArrayList<Object>();
        list.add(1);      // Integer
        list.add(2.5);    // Double
        list.add(3L);     // Long
        System.out.println(list);
    }
}

أسلوب Collections.addAll

يستخدم JDK الحدود السفلى للمجموعات المستقبِلة. ومن أمثلة ذلك طريقة عامة تدفع العناصر إلى وجهة.

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

public class Main {
    @SafeVarargs
    static <T> void addAll(List<? super T> dest, T... items) {
        for (T item : items) dest.add(item);
    }
    public static void main(String[] args) {
        List<Object> sink = new ArrayList<>();
        addAll(sink, "a", "b", "c");
        System.out.println(sink);
    }
}

Comparator مع super

من الاستخدامات العملية: يتيح Comparator<? super T> للفرز قبول مقارن مكتوب لنوع فائق.

يمكن لمقارن يقارن أي Object باستخدام toString أن يفرز قائمة من السلاسل النصية.

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

public class Main {
    public static void main(String[] args) {
        Comparator<Object> byString = Comparator.comparing(Object::toString);
        List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
        names.sort(byString); // List<String>.sort accepts Comparator<? super String>
        System.out.println(names);
    }
}

‏super وextends متعاكسان

محرفا البدل متعاكسان:

  • ? extends T: قراءة T، ولا يمكن الكتابة. وهو منتِج.
  • ? super T: كتابة T، والقراءة باعتبارها Object فقط. وهو مستهلِك.

هذا التناظر هو جوهر قاعدة PECS التي ستتعلمها بعد ذلك.

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

public class Main {
    public static void main(String[] args) {
        List<? super Integer> consumer = new ArrayList<Number>();
        consumer.add(1);
        System.out.println("consumer can write: " + consumer);
    }
}

النسخ بين الحدود

تُظهر طريقة النسخ محرفي البدل معًا: القراءة من ? extends T والكتابة إلى ? super T.

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

public class Main {
    static <T> void copy(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Integer> src = List.of(1, 2, 3);
        List<Number> dest = new ArrayList<>();
        copy(src, dest);
        System.out.println(dest);
    }
}

متى لا تستخدم محرف بدل

إذا كانت الطريقة تقرأ T وتكتبه معًا، فلا تستخدم محرف بدل. استخدم نوعًا محددًا أو معلمة نوع مسمّاة.

توجد محارف البدل تحديدًا لحالات القراءة فقط أو الكتابة فقط.

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

public class Main {
    static <T> void swapFirstTwo(List<T> list) {
        T tmp = list.get(0);
        list.set(0, list.get(1));
        list.set(1, tmp);
    }
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("a", "b"));
        swapFirstTwo(list);
        System.out.println(list);
    }
}

تحقق سريع

اختبر مدى فهمك للحدود السفلى.

مراجعة

لقد تعلمت محارف البدل ذات الحدود السفلى:

  • ? super T يعني نوعًا فائقًا غير معروف لـ T.
  • يمكنك كتابة T وأنواعه الفرعية (أي أن المجموعة مستهلِك).
  • تُرجع عمليات القراءة Object فقط.
  • وهو يعكس ? extends T تمامًا.

بعد ذلك، سنتناول القاعدة التي تجمع بينهما: PECS.

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

public class Main {
    public static void main(String[] args) {
        List<? super Integer> list = new ArrayList<Number>();
        list.add(42);
        System.out.println("Lower bound recap: " + list);
    }
}

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

هل درس «Wildcards ذات الحد السفلي» مجاني؟

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

ماذا ستتعلم في «Wildcards ذات الحد السفلي»؟

? super T للمستهلِكات تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

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

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

كم من الوقت يستغرق درس «Wildcards ذات الحد السفلي»؟

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

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

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

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

  1. Wildcards ذات الحد العلوي
  2. Wildcards ذات الحد السفلي
  3. مبدأ PECS
  4. Wildcards في واجهات البرمجة
← العودة إلى Java Academy