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 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 ListesiAlt 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 (generic) 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ürYardı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.
Görev
KolayHer üç 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 birname(String) alanına, bunu başlatan bir kurucuya (constructor) ve birgetName()metoduna sahip birFoodtemel 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 (kurucusuper(name)çağrısı yapar) veVegetable, Food sınıfını genişletir (aynı yapı).Animal.java: Özel birspecies(String) alanına, bir kurucuya ve birgetSpecies()metoduna sahip birAnimaltemel 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ğıranCarnivoreveHerbivore.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 öğeyitoString()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ıintolarak döndürün. Bu, bir üreticiden (producer) okuma yapmayı gösterir.addMeatToStock(List<? super Meat> stock, String meatName)- Meat tutabilen bir listeye yazma yapmak için alttan sınırlı bir joker karakter kullanır. Verilen isimle yeni birMeatnesnesi 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).İlk olarak, bir
ArrayList<Food>oluşturun ve et ismiyle birMeatnesnesi, sebze ismiyle birVegetablenesnesi ekleyin.Food inventory:yazdırın ve ardından bu liste ileprintInventorymetodunu çağırın.Ardından, boş bir satır yazdırın, sonra yemek listeniz üzerinde
calculateTotalFoodkullanarakTotal food items: [count]yazdırın.Son olarak,
meatStockadında yeni birArrayList<Food>oluşturun. Boş bir satır yazdırın, ardındanAdding to meat stock...yazdırın. Bu liste ve"Beef"dizesi ileaddMeatToStockmetodunu çağırın. SonraMeat stock after adding:yazdırın ve et stoğu üzerindeprintInventorymetodunu ç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!
Kopya kağıdı
Java, tam tür parametresi bilinmediğinde veya ilgisiz olduğunda genel (generic) türlerle çalışmak için üç tür joker karakter (wildcard) sağlar.
Sınırsız Joker Karakter (?)
Bilinmeyen bir türü temsil eder ve herhangi bir parametreli türü kabul eder:
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 veri 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 ListesiAlt Sınırlı Joker Karakter (? super Type)
Belirtilen türü veya onun üst sınıflarından herhangi birini kabul eder. Genel bir yapıya veri yazmanız gerektiğinde 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ürPECS Prensibi
Producer Extends, Consumer Super (Üretici Extends, Tüketici Super): Sadece okuma yaparken (üretici) extends, sadece yazma yaparken (tüketici) super kullanın.
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 fonksiyonunu ç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 fonksiyonunu çağırın
// TODO: "Meat stock after adding:" yazdırın, ardından meatStock üzerinde printInventory fonksiyonunu çağırın
}
}
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
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesnelerthis Anahtar KelimesiMetotlarAlanlar (Öznitelikler)Yapıcı MetotYapıcı Metot Aşırı YüklemeÖzet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtım (extends)super Anahtar KelimesiMetot Geçersiz Kılma (@Override)Yapıcı Metot ZincirlemeObject SınıfıTekli ve Çok Seviyeli KalıtımNeden Çoklu Sınıf Kalıtımı Yok?Özet - Çalışan Hiyerarşisi7Özel Metotlar ve Object Sınıfı
toString() Metoduequals() ve hashCode()clone() MetoducompareTo() ve ComparableComparator ArayüzüÖzet - Özel Sıralama2Erişim Belirleyiciler ve Kapsülleme
Erişim Seviyelerine Genel BakışGetter ve Setter MetotlarıBilgi Gizlemefinal Anahtar KelimesiÖzet - Banka Hesabı Yöneticisi5Polimorfizm
Metot Aşırı Yükleme TemelleriMetot Geçersiz Kılma (Çalışma Zamanı)Upcasting ve Downcastinginstanceof OperatörüSoyut Sınıflar ve MetotlarÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımAgregasyon vs KompozisyonDahili, Yuvalanmış ve Anonim SınıflarEnum'lar ve Enum MetotlarıRecords (Java 16+)Sealed Classes (Java 17+)11Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıBuilder KalıbıObserver KalıbıStrategy Kalıbı14Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi3Sınıf Özellikleri ve Statik Üyeler
Instance ve Statik DeğişkenlerStatik MetotlarStatik BloklarSabitler (static final)Özet - Sayaç ve Utility6Arayüzler ve Soyut Sınıflar
Arayüzlere GirişArayüzleri UygulamaÇoklu Arayüz UygulamaArayüzlerde Default ve StaticSoyut Sınıflar ve ArayüzlerFonksiyonel ArayüzlerÖzet - Ödeme Sistemi9Generics
Generics'e GirişGeneric SınıflarGeneric MetotlarSınırlandırılmış Tip ParametreleriWildcard'lar (?, extends, super)Özet - Generic Container12Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıYineleyici Kalıbı