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ı tür parametreleri, jenerikleri belirli türlerle kısıtlar; ancak mevcut jenerik türlerle çalışırken tam tür parametresini bilmiyorsanız veya önemsemiyorsanız ne olacak? İşte joker karakterler burada 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 kılavuz: yalnızca okuma yaptığınızda (üretici) extends kullanın, yalnızca yazma yaptığınızda (tüketici) super kullanın. Bu, PECS ilkesi olarak bilinir: Üretici Extends, Tüketici 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ı metotlar yazacaksın.

Kodunu dört dosyaya ayıracaksın:

  • Food.java: Yiyecekler için basit bir sınıf hiyerarşisi oluştur: Food adlı, name (String) adında private bir alanı, bunu başlatan bir kurucusu ve bir getName() metodu olan temel sınıfla başla. Ardından aynı dosyada iki alt sınıf oluştur: Meat, Food sınıfını genişletsin (kurucusu super(name) çağrısını yapsın) ve Vegetable, Food sınıfını genişletsin (aynı düzeni kullansın).
  • Animal.java: Animal (String) adında private bir alanı, bir kurucusu ve bir species metodu olan temel getSpecies() sınıfını oluştur. İki alt sınıf oluştur: Carnivore ve Herbivore; her biri Animal sınıfını genişletsin ve üst sınıfın kurucusunu çağırsın.
  • ZooFeeder.java: Joker karakterlerin öne çıktığı yer burası! Üç static metodu olan 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ü kur ve her öğeyi toString() kullanarak satır başına bir öğe 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ı bir int olarak döndür. Bu, bir üreticiden okuma işlemini 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 yazma işlemini 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).

    Önce 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 metodunu çağır.

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

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

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

Yazdırmanın doğru çalışması için Food sınıfında toString() metodunu, yiyeceğin adını döndürecek şekilde geçersiz kıl. Her joker karakter türünün farklı bir amaca hizmet ettiğine dikkat et: yalnızca Object olarak okuma yapman 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ş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