Java Academy · درس

Wildcards في واجهات البرمجة

تصميم دوال عامة مرنة

الدرس 4 من 413 خطوة

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

تصميم طرق مرنة

تُعد محارف البدل أداةً مخصصة أساسًا لـمصممي واجهات برمجة التطبيقات. فمحرف بدل موضوع في المكان المناسب يتيح للمستدعين تمرير أنواع أكثر من دون عمليات تحويل.

الهدف هو تحقيق أقصى مرونة للمستدعين، مع الحفاظ على أمان الأنواع بالكامل داخل الطريقة.

import java.util.List;

public class Main {
    static double total(List<? extends Number> items) {
        double sum = 0;
        for (Number n : items) sum += n.doubleValue();
        return sum;
    }
    public static void main(String[] args) {
        System.out.println(total(List.of(1, 2, 3)));
        System.out.println(total(List.of(1.5, 2.5)));
    }
}

محارف البدل غير المحدودة

List<?> هو محرف بدل غير محدود: قائمة من نوع غير معروف.

استخدمه عندما لا تهتم طريقتك بنوع العناصر، مثل عدّ العناصر أو التحقق من فراغ القائمة.

import java.util.List;

public class Main {
    static int size(List<?> any) {
        return any.size();
    }
    public static void main(String[] args) {
        System.out.println(size(List.of("a", "b")));
        System.out.println(size(List.of(1, 2, 3)));
    }
}

‏List<?> مقارنةً بـ List<Object>

هذان النوعان مختلفان. يقبل List<Object> قائمة مصرّحًا عنها من النوع Object فقط، بينما يقبل List<?> قائمة من أي نوع.

يمكنك تمرير List<String> إلى معلمة من النوع List<?>، لكن لا يمكنك تمريرها إلى معلمة من النوع List<Object>.

import java.util.List;

public class Main {
    static void printAll(List<?> list) {
        for (Object o : list) System.out.println(o);
    }
    public static void main(String[] args) {
        List<String> names = List.of("Ada", "Linus");
        printAll(names); // works; List<Object> would reject this
    }
}

متى تكون معلمة النوع أوضح

إذا احتجت إلى الإشارة إلى نوع العنصر أكثر من مرة، فستكون معلمة النوع المسمّاة أوضح من محرف البدل.

قارن بين void swap(List<?> l, int i, int j) (التي تحتاج إلى مساعد خاص) وبين نسخة عامة واضحة.

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

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

حيلة التقاط محرف البدل باستخدام مساعد

إذا كان يجب أن تستخدم واجهة برمجة التطبيقات العامة List<?>، فيمكنك تفويض العمل إلى مساعد عام خاص من أجل التقاط محرف البدل.

يسمّي المساعد النوع T حتى يتمكن من الكتابة مجددًا في القائمة.

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

public class Main {
    public static void reverse(List<?> list) { reverseHelper(list); }
    private static <T> void reverseHelper(List<T> list) {
        for (int i = 0, j = list.size() - 1; i < j; i++, j--) {
            T tmp = list.get(i);
            list.set(i, list.get(j));
            list.set(j, tmp);
        }
    }
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4));
        reverse(list);
        System.out.println(list);
    }
}

معلمات المنتِج في واجهة برمجة تطبيقات حقيقية

يتطلب تصميم طريقة addAll التي تسحب من أي مصدر متوافق استخدام حد علوي للمصدر.

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

public class Main {
    static <T> void addAll(List<T> target, Collection<? extends T> source) {
        for (T t : source) target.add(t);
    }
    public static void main(String[] args) {
        List<Number> nums = new ArrayList<>();
        addAll(nums, List.of(1, 2, 3));
        System.out.println(nums);
    }
}

معلمات المستهلِك في واجهة برمجة تطبيقات حقيقية

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

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

public class Main {
    static <T> void repeat(T value, int times, List<? super T> sink) {
        for (int i = 0; i < times; i++) sink.add(value);
    }
    public static void main(String[] args) {
        List<Object> out = new ArrayList<>();
        repeat("hi", 3, out);
        System.out.println(out);
    }
}

محارف البدل مع الأنواع العامة المتداخلة

غالبًا ما تحتاج الأنواع العامة المتداخلة إلى محارف بدل. فالطريقة التي تقبل قائمة من أي نوع من القوائم تستخدم List<? extends List<?>>.

import java.util.List;

public class Main {
    static int countAll(List<? extends List<?>> lists) {
        int total = 0;
        for (List<?> inner : lists) total += inner.size();
        return total;
    }
    public static void main(String[] args) {
        System.out.println(countAll(List.of(List.of(1, 2), List.of("a", "b", "c"))));
    }
}

تجنّب الإفراط في استخدام الأنواع العامة

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

أضف محارف البدل عندما تلاحظ أن عدم التغاير يمنع مستدعين حقيقيين، لا بشكل استباقي.

import java.util.List;

public class Main {
    // Simple and clear; no wildcard needed for this internal use
    static String joinStrings(List<String> parts) {
        return String.join(", ", parts);
    }
    public static void main(String[] args) {
        System.out.println(joinStrings(List.of("a", "b", "c")));
    }
}

توثيق الغرض من محرف البدل

يشير محرف البدل إلى الغرض. يخبر ? extends T القراء بأن "هذه القيمة للقراءة فقط"، بينما يقول ? super T إن "هذه القيمة للكتابة فقط".

اختيار محرف البدل المناسب هو شكل من أشكال الكود الموثّق ذاتيًا، كما أنه يفرض العقد.

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

public class Main {
    // src: read-only producer; dest: write-only consumer
    static <T> void transfer(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Number> dest = new ArrayList<>();
        transfer(List.of(1, 2), dest);
        System.out.println(dest);
    }
}

واجهة برمجة تطبيقات عامة للمكدس

مثال Bloch الشهير للمكدس: تستهلك pushAll العناصر من منتِج (extends)، بينما تنتج popAll العناصر إلى مستهلِك (super).

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.ArrayList;
import java.util.List;

public class Main {
    static class Stack<E> {
        private final Deque<E> items = new ArrayDeque<>();
        void pushAll(Collection<? extends E> src) { for (E e : src) items.push(e); }
        void popAll(Collection<? super E> dst) { while (!items.isEmpty()) dst.add(items.pop()); }
    }
    public static void main(String[] args) {
        Stack<Integer> s = new Stack<>();
        s.pushAll(List.of(1, 2, 3));
        List<Number> out = new ArrayList<>();
        s.popAll(out);
        System.out.println(out);
    }
}

تحقق سريع

اختبر حدسك في تصميم واجهات برمجة التطبيقات.

مراجعة

لقد تعلمت تصميم واجهات برمجة التطبيقات باستخدام محارف البدل:

  • List<?> للطرق المخصّصة للقراءة فقط والتي لا تعتمد على نوع محدد.
  • طبّق PECS على المعلمات لتحقيق المرونة.
  • استخدم حيلة التقاط محرف البدل بواسطة مساعد الخاص عندما تضطر إلى الكتابة من خلال محرف بدل.
  • تجنّب محارف البدل في أنواع الإرجاع، ولا تفرط في استخدام الأنواع العامة.

لقد أكملت دورة محارف البدل وPECS.

public class Main {
    public static void main(String[] args) {
        System.out.println("Wildcards in APIs course complete");
    }
}
البدء مجانًا

تعلم Java مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
104
الدروس
374

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

هل درس «Wildcards في واجهات البرمجة» مجاني؟

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

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

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

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

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

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

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

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

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

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

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