Menu
Coddy logo textTech

Wildcard'lar (?, extends, super)

Coddy'nin Java Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 57 / 87.

Sınırlı tip parametreleri, jenerikleri belirli tiplerle kısıtlar; ancak mevcut jenerik tiplerle çalışırken tam tip parametresini bilmediğinizde veya önemsemediğinizde ne olur? İşte burada joker karakterler (wildcards) devreye girer.

Sınırsız joker karakter (unbounded wildcard) ?, bilinmeyen bir türü temsil eder. Herhangi bir parametreli türü kabul etmek istediğinizde kullanışlıdır:

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

printList(new ArrayList<String>());   // Çalışır
printList(new ArrayList<Integer>());  // Çalışır

Üstten sınırlı joker karakter (upper bounded wildcard) ? extends Type, belirtilen türü veya onun herhangi bir alt sınıfını kabul eder. Genel (generic) bir yapıdan veri okumanız gerektiğinde bunu kullanın:

public static double sumNumbers(List<? extends Number> numbers) {
    double sum = 0;
    for (Number n : numbers) {
        sum += n.doubleValue();
    }
    return sum;
}

sumNumbers(Arrays.asList(1, 2, 3));        // Integer listesi
sumNumbers(Arrays.asList(1.5, 2.5));       // Double listesi

Alt sınırlı joker karakter (lower bounded wildcard) ? super Type, belirtilen türü veya onun herhangi bir üst sınıfını kabul eder. Genel bir yapıya yazmanız gerektiğinde bunu kullanın:

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

List<Number> numbers = new ArrayList<>();
addIntegers(numbers);  // Çalışır - Number, Integer'ın bir üst türüdür

Yardımcı bir kural: yalnızca okuma yaparken (üretici) extends kullanın, yalnızca yazma yaparken (tüketici) super kullanın. Bu, PECS prensibi olarak bilinir—Producer Extends, Consumer Super.

challenge icon

Görev

Kolay

Her üç joker karakter (wildcard) türünü de gösteren bir hayvanat bahçesi besleme sistemi kuralım! Hayvanlar ve yiyeceklerden oluşan bir hiyerarşi oluşturacak, ardından farklı besleme senaryolarını yönetmek için sınırsız (unbounded), üstten sınırlı (upper bounded) ve alttan sınırlı (lower bounded) joker karakterleri kullanan yardımcı metotlar yazacaksınız.

Kodunuzu dört dosya halinde düzenleyeceksiniz:

  • Food.java: Yiyecekler için basit bir sınıf hiyerarşisi oluşturun. Özel bir name (String) alanına, bunu başlatan bir kurucuya (constructor) ve bir getName() metoduna sahip temel bir Food sınıfı ile başlayın. Ardından aynı dosyada iki alt sınıf oluşturun: Meat, Food sınıfını genişletir (kurucu super(name) çağrısı yapar) ve Vegetable, Food sınıfını genişletir (aynı yapı).
  • Animal.java: Özel bir species (String) alanına, bir kurucuya ve bir getSpecies() metoduna sahip temel bir Animal sınıfı oluşturun. İki alt sınıf oluşturun: Her biri Animal sınıfını genişleten ve üst sınıf kurucusunu çağıran Carnivore ve Herbivore.
  • ZooFeeder.java: Joker karakterlerin parladığı yer burası! Üç statik metoda sahip bir yardımcı sınıf oluşturun:

    printInventory(List<?> items) - Herhangi bir listeyi yazdırmak için sınırsız bir joker karakter kullanır. Liste üzerinde döngü kurun ve her öğeyi toString() kullanarak her satıra bir tane gelecek şekilde yazdırın.

    calculateTotalFood(List<? extends Food> foods) - Herhangi bir Food türündeki listeden okuma yapmak için üstten sınırlı bir joker karakter kullanır. Öğelerin sayısını int olarak döndürün. Bu, bir üreticiden (producer) okuma yapmayı gösterir.

    addMeatToStock(List<? super Meat> stock, String meatName) - Meat nesnesi tutabilen bir listeye yazma yapmak için alttan sınırlı bir joker karakter kullanır. Verilen isimle yeni bir Meat nesnesi oluşturun ve bunu stoğa ekleyin. Bu, bir tüketiciye (consumer) yazma yapmayı gösterir.

  • Main.java: Hayvanat bahçesi besleme sisteminizi bir araya getirin! İki girdi alacaksınız: bir et ismi (String) ve bir sebze ismi (String).

    Önce bir ArrayList<Food> oluşturun ve et ismiyle bir Meat nesnesi, sebze ismiyle bir Vegetable nesnesi ekleyin. Food inventory: yazdırın, ardından bu listeyle printInventory metodunu çağırın.

    Ardından, boş bir satır yazdırın, sonra yemek listeniz üzerinde calculateTotalFood kullanarak Total food items: [count] yazdırın.

    Son olarak, meatStock adında yeni bir ArrayList<Food> oluşturun. Boş bir satır yazdırın, ardından Adding to meat stock... yazdırın. Bu liste ve "Beef" dizesi ile addMeatToStock metodunu çağırın. Sonra Meat stock after adding: yazdırın ve et stoğu üzerinde printInventory metodunu çağırın.

Sırasıyla iki girdi alacaksınız: bir et ismi ve bir sebze ismi.

Yazdırma işleminin doğru çalışması için Food sınıfınızda toString() metodunu yiyeceğin adını döndürecek şekilde geçersiz kılın (override). Her joker karakter türünün nasıl farklı bir amaca hizmet ettiğine dikkat edin: Sadece Object olarak okumanız gerektiğinde maksimum esneklik için ?, belirli türleri okurken ? extends ve bir koleksiyona yazarken ? super!

Kendin dene

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

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String meatName = scanner.nextLine();
        String vegetableName = scanner.nextLine();
        
        // TODO: Bir ArrayList<Food> oluşturun ve Meat ile Vegetable nesnelerini ekleyin
        
        // TODO: "Food inventory:" yazdırın, ardından printInventory metodunu çağırın
        
        // TODO: Boş bir satır yazdırın, ardından calculateTotalFood kullanarak "Total food items: [count]" yazdırın
        
        // TODO: meatStock adında yeni bir ArrayList<Food> oluşturun
        
        // TODO: Boş bir satır yazdırın, ardından "Adding to meat stock..." yazdırın
        
        // TODO: meatStock ve "Beef" ile addMeatToStock metodunu çağırın
        
        // TODO: "Meat stock after adding:" yazdırın, ardından meatStock üzerinde printInventory metodunu çağırın
    }
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler