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.

bounded tür parametreleri generic türleri belirli türlerle sınırlar, ancak mevcut generic türlerle çalışırken tam tür parametresini bilmiyorsanız veya bunu önemsemiyorsanız ne olur? İşte burada wildcards devreye girer.

sınırsız joker karakter ?, 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

Üst sınırlı joker karakter ? extends Type, belirtilen türü veya onun alt sınıflarından herhangi birini kabul eder. Genel bir yapıdan okumanız gerektiğinde 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ırlandırılmış joker karakter ? 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 tipidir

Yararlı bir kural: yalnızca okuma (üretici) yaptığında extends, yalnızca yazma (tüketici) yaptığında super kullan. Bu, PECS ilkesi olarak bilinir: Producer Extends, Consumer Super.

challenge icon

Görev

Kolay

Her üç joker karakter türünü de gösteren bir hayvanat bahçesi besleme sistemi oluşturalım! Bir hayvan ve yiyecek hiyerarşisi oluşturacak, ardından farklı besleme senaryolarını ele almak için sınırsız, üst sınırlandırılmış ve alt sınırlandırılmış joker karakterler kullanan yardımcı yöntemler yazacaksın.

Kodunu dört dosyaya düzenleyeceksin:

  • Food.java: Yiyecekler için basit bir sınıf hiyerarşisi oluştur. Özel bir name alanına (String), bunu başlatmak için bir kurucuya ve bir getName() yöntemine sahip bir temel Food sınıfıyla başla. Ardından aynı dosyada iki alt sınıf oluştur: Meat extends Food (kurucu super(name) çağrısı yapar) ve Vegetable extends Food (aynı düzen).
  • Animal.java: Özel bir species alanına (String), bir kurucuya ve bir getSpecies() yöntemine sahip bir temel Animal sınıfı oluştur. İki alt sınıf oluştur: Her biri Animal sınıfını genişleten ve üst sınıf kurucusunu çağıran Carnivore ve Herbivore.
  • ZooFeeder.java: Joker karakterlerin öne çıktığı yer burası! Üç statik yönteme sahip bir yardımcı sınıf oluştur:

    printInventory(List<?> items) - Herhangi bir listeyi yazdırmak için sınırsız bir joker karakter kullanır. Liste üzerinde döngü oluştur ve her itemtoString() kullanarak satır başına bir tane olacak şekilde yazdır.

    calculateTotalFood(List<? extends Food> foods) - Herhangi bir Food türündeki listeden okumak için üst sınırlandırılmış bir joker karakter kullanır. Öğe sayısını int olarak döndür. Bu, bir üreticiden okumayı gösterir.

    addMeatToStock(List<? super Meat> stock, String meatName) - Meat tutabilen bir listeye yazmak için alt sınırlandırılmış bir joker karakter kullanır. Verilen adla yeni bir Meat nesnesi oluştur ve bunu stoğa ekle. Bu, bir tüketiciye yazmayı gösterir.

  • Main.java: Hayvanat bahçesi besleme sistemini bir araya getir! İki girdi alacaksın: bir et adı (String) ve bir sebze adı (String).

    İlk olarak bir ArrayList<Food> oluştur ve et adıyla bir Meat nesnesi ile sebze adıyla bir Vegetable nesnesi ekle. Food inventory: yazdır, ardından bu listeyle printInventory çağrısı yap.

    Sonra boş bir satır yazdır, ardından yiyecek listende calculateTotalFood kullanarak Total food items: [count] yazdır.

    Son olarak meatStock olarak adlandırılan yeni bir ArrayList<Food> oluştur. Boş bir satır yazdır, ardından Adding to meat stock... yazdır. Bu liste ve "Beef" dizesiyle addMeatToStock çağrısı yap. Ardından Meat stock after adding: yazdır ve et stoğu üzerinde printInventory çağrısı yap.

İki girdiyi şu sırayla alacaksın: bir et adı ve bir sebze adı.

Yiyecek adını döndürmesi için Food sınıfında toString() yöntemini geçersiz kıl; böylece yazdırma düzgün çalışır. Her joker karakter türünün farklı bir amaca nasıl hizmet ettiğine dikkat et: yalnızca Object olarak okumaya ihtiyaç duyduğunda 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ştur ve Meat ve Vegetable nesneleri ekle
        
        // TODO: Print "Food inventory:" then call printInventory
        
        // TODO: Print blank line, then "Total food items: [count]" using calculateTotalFood
        
        // TODO: meatStock adında yeni bir ArrayList<Food> oluştur
        
        // TODO: Print blank line, then "Adding to meat stock..."
        
        // TODO: addMeatToStock'u meatStock ve "Beef" ile çağır
        
        // TODO: Print "Meat stock after adding:" then call printInventory on meatStock
    }
}
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

Kendi başına pratik yap: Online Java derleyicisi