Generics

Generics تسمح لك بكتابة كود يعمل مع أي نوع بيانات. في هذا الدرس، سنتعلم كيفية استخدامها.

لماذا Generics؟

بدون Generics:

JAVA
List list = new ArrayList();
list.add("نص");
list.add(123);  // يمكن إضافة أي نوع
String s = (String) list.get(1);  // ❌ خطأ أثناء التشغيل!

مع Generics:

JAVA
List<String> list = new ArrayList<>();
list.add("نص");
// list.add(123);  // ❌ خطأ أثناء الترجمة!
String s = list.get(0);  // ✅ آمن

Generics مع الفئات

JAVA
public class Box<T> {
    private T content;
    
    public Box(T content) {
        this.content = content;
    }
    
    public T getContent() {
        return content;
    }
    
    public void setContent(T content) {
        this.content = content;
    }
}

// الاستخدام
Box<String> stringBox = new Box<>("مرحباً");
String text = stringBox.getContent();  // لا حاجة للتحويل

Box<Integer> intBox = new Box<>(42);
int number = intBox.getContent();  // Auto-unboxing

Generics مع عدة أنواع

JAVA
public class Pair<K, V> {
    private K key;
    private V value;
    
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    
    public K getKey() { return key; }
    public V getValue() { return value; }
}

// الاستخدام
Pair<String, Integer> pair = new Pair<>("أحمد", 25);
String name = pair.getKey();
int age = pair.getValue();

Generics مع الدوال

JAVA
public static <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.print(element + " ");
    }
    System.out.println();
}

// الاستخدام
String[] names = {"أحمد", "محمد", "علي"};
Integer[] numbers = {1, 2, 3, 4, 5};

printArray(names);   // أحمد محمد علي
printArray(numbers); // 1 2 3 4 5

Boundaries — تحديد النطاق

extends — نوع فرعي

JAVA
// T يجب أن يكون Number أو فئة فرعية
public static <T extends Number> double sum(List<T> list) {
    double total = 0;
    for (T num : list) {
        total += num.doubleValue();
    }
    return total;
}

// الاستخدام
List<Integer> ints = List.of(1, 2, 3);
List<Double> doubles = List.of(1.5, 2.5, 3.5);

System.out.println(sum(ints));     // 6.0
System.out.println(sum(doubles));  // 7.5

implements — تنفيذ واجهة

JAVA
// T يجب أن ينفذ Comparable
public static <T extends Comparable<T>> T findMax(List<T> list) {
    T max = list.get(0);
    for (T item : list) {
        if (item.compareTo(max) > 0) {
            max = item;
        }
    }
    return max;
}

Wildcards — أحرف البدل

? — أي نوع

JAVA
public static void printList(List<?> list) {
    for (Object item : list) {
        System.out.println(item);
    }
}

? extends — نوع فرعي

JAVA
public static double sumNumbers(List<? extends Number> list) {
    double total = 0;
    for (Number num : list) {
        total += num.doubleValue();
    }
    return total;
}

? super — نوع أبوي

JAVA
public static void addNumbers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
    list.add(3);
}

مثال: Stack عام

JAVA
import java.util.ArrayList;
import java.util.EmptyStackException;

public class Stack<T> {
    private ArrayList<T> elements = new ArrayList<>();
    
    public void push(T item) {
        elements.add(item);
    }
    
    public T pop() {
        if (elements.isEmpty()) {
            throw new EmptyStackException();
        }
        return elements.remove(elements.size() - 1);
    }
    
    public T peek() {
        if (elements.isEmpty()) {
            throw new EmptyStackException();
        }
        return elements.get(elements.size() - 1);
    }
    
    public boolean isEmpty() {
        return elements.isEmpty();
    }
    
    public int size() {
        return elements.size();
    }
}

// الاستخدام
Stack<Integer> intStack = new Stack<>();
intStack.push(1);
intStack.push(2);
intStack.push(3);
System.out.println(intStack.pop());  // 3

Stack<String> stringStack = new Stack<>();
stringStack.push("أحمد");
stringStack.push("محمد");
System.out.println(stringStack.pop());  // محمد

❓ أسئلة شائعة

س ما هو Type Erasure؟
ج Java تحذف معلومات Generics أثناء التشغيل. هذا يعني أن Generics معلومات فقط للترجمة.
س لماذا لا أستطيع استخدام int مع Generics؟
ج Generics تعمل فقط مع الفئات. استخدم Integer بدلاً من int.

س:ما الفرق بين extends و super؟ extends: نوع فرعي (للقراءة). super: نوع أبوي (للكتابة).

📖 ملخص

📝 تمارين

  1. صندوق: أنشئ Box مع دوال get و set
  2. زوج: أنشئ Pair<K, V> لتخزين زوج من القيم
  3. مكدس: أنشئ Stack مع push و pop و peek

الدرس التالي

في الدرس التالي، سنتعلم ممارسة Collections — تطبيقات عملية.

100%