CodeGym/Java Blogu/Rastgele/Jeneriklerdeki joker karakterler
John Squirrels
Seviye
San Francisco

Jeneriklerdeki joker karakterler

grupta yayınlandı
MERHABA! Jenerik çalışmamıza devam edelim. Onlar hakkında önceki derslerde zaten önemli miktarda bilgi edindiniz ( jeneriklerle çalışırken vararg'ları kullanma ve tip silme hakkında ), ancak henüz ele almadığımız önemli bir konu var: joker karakterler . Bu jeneriklerin çok önemli bir özelliğidir. Öyle ki ona ayrı bir ders ayırdık! Bununla birlikte, joker karakterler konusunda özellikle karmaşık bir şey yoktur. Hemen göreceksiniz :) Jeneriklerdeki joker karakterler - 1Bir örneğe bakalım:
public class Main {

   public static void main(String[] args) {

       String str = new String("Test!");
       // No problem
       Object obj = str;

       List<String> strings = new ArrayList<String>();
       // Compilation error!
       List<Object> objects = strings;
   }
}
Burada neler oluyor? Çok benzer iki durum görüyoruz. StringBu durumda, bir nesneyi bir nesneye atarız Object. Burada sorun yok — her şey beklendiği gibi çalışıyor. Ancak ikinci durumda derleyici bir hata üretir. Ama aynı şeyi yapıyoruz, değil mi? Bu sefer sadece birkaç nesneden oluşan bir koleksiyon kullanıyoruz. Ancak hata neden oluşuyor? Fark ne? StringBir nesneyi bir Objectveya 20 nesneye mi atıyoruz ? Bir nesne ile bir nesneler koleksiyonu arasında önemli bir ayrım vardır . Sınıf, Bsınıfın bir alt öğesiyse A, o zaman Collection<B>öğesinin bir alt öğesi değildir Collection<A>. List<String>Bu yüzden bir oyuncumuzu alamadık.List<Object>. String'nin çocuğudur Object, ama ' List<String>nin çocuğu değildir List<Object>. Bu süper sezgisel görünmeyebilir. Dilin yaratıcıları neden bu şekilde yaptı? Derleyicinin bize bir hata vermediğini düşünelim:
List<String> strings = new ArrayList<String>();
List<Object> objects = strings;
Bu durumda, örneğin aşağıdakileri yapabiliriz:
objects.add(new Object());
String s = strings.get(0);
Derleyici bize herhangi bir hata vermediğinden ve List<Object>işaret eden bir referans oluşturmamıza izin verdiğinden, koleksiyona stringsherhangi bir eski nesneyi ekleyebiliriz ! Bu nedenle, koleksiyonumuzun yalnızca invocation genel türünde type bağımsız değişkeni tarafından belirtilen nesneleri içerdiği garantisini kaybettik . Başka bir deyişle, jenerik ilaçların ana avantajı olan tip güvenliğini kaybettik. Ve derleyici bunu yapmamızı engellemediği için, yalnızca çalışma zamanında bir hata alırız ki bu her zaman bir derleme hatasından çok daha kötüdür. Bu gibi durumları önlemek için derleyici bize bir hata veriyor: ObjectstringsString
// Compilation error
List<Object> objects = strings;
... ve List<String>soyundan olmadığını bize hatırlatıyor List<Object>. Bu, jenerik ilaçlar için katı bir kuraldır ve onlarla çalışırken hatırlanması gerekir. Hadi devam edelim. Küçük bir sınıf hiyerarşimiz olduğunu varsayalım:
public class Animal {

   public void feed() {

       System.out.println("Animal.feed()");
   }
}

public class Pet extends Animal {

   public void call() {

       System.out.println("Pet.call()");
   }
}

public class Cat extends Pet {

   public void meow() {

       System.out.println("Cat.meow()");
   }
}
Hiyerarşinin tepesinde, Pet tarafından miras alınan basit bir Animal sınıfı bulunur. Pet'in 2 alt sınıfı vardır: Köpek ve Kedi. Şimdi basit bir metod oluşturmamız gerektiğini varsayalım iterateAnimals(). AnimalYöntem, herhangi bir hayvanın ( , Pet, Cat, ) bir koleksiyonunu almalı Dog, tüm öğeler üzerinde yineleme yapmalı ve her yineleme sırasında konsolda bir mesaj göstermelidir. Böyle bir yöntem yazmaya çalışalım:
public static void iterateAnimals(Collection<Animal> animals) {

   for(Animal animal: animals) {

       System.out.println("Another iteration in the loop!");
   }
}
Görünüşe göre sorun çözüldü! Ancak, son zamanlarda öğrendiğimiz gibi, List<Cat>ve List<Dog>torunları List<Pet>değiliz List<Animal>! iterateAnimals()Bu , yöntemi bir kedi listesiyle çağırmaya çalıştığımızda bir derleme hatası aldığımız anlamına gelir :
import java.util.*;

public class Main3 {


   public static void iterateAnimals(Collection<Animal> animals) {

       for(Animal animal: animals) {

           System.out.println("Another iteration in the loop!");
       }
   }

   public static void main(String[] args) {


       List<Cat> cats = new ArrayList<>();
       cats.add(new Cat());
       cats.add(new Cat());
       cats.add(new Cat());
       cats.add(new Cat());

       // Compilation error!
       iterateAnimals(cats);
   }
}
Durum bizim için pek iyi görünmüyor! Her tür hayvanı numaralandırmak için ayrı yöntemler yazmak zorunda mıyız? Aslında hayır, yapmıyoruz :) Ve tesadüfen, joker karakterler bu konuda bize yardımcı oluyor! Aşağıdaki yapıyı kullanarak sorunu basit bir yöntemle çözebiliriz:
public static void iterateAnimals(Collection<? extends Animal> animals) {

   for(Animal animal: animals) {

       System.out.println("Another iteration in the loop!");
   }
}
Bu bir joker karakterdir. Daha doğrusu, bu, çeşitli joker karakter türlerinin ilkidir. Üst sınır joker karakterleri olarak bilinir ve ? uzanır . Bu yapı bize ne anlatıyor? Bu, yöntemin bir nesne koleksiyonunu veya (? Extends Animal) Animalsınıfından türeyen herhangi bir sınıftaki nesne koleksiyonunu kabul ettiği anlamına gelir. AnimalBaşka bir deyişle, yöntem Animal, Pet, Dogveya Catnesnelerin bir koleksiyonunu kabul edebilir - fark etmez. İşe yaradığına kendimizi inandıralım:
public static void main(String[] args) {

   List<Animal> animals = new ArrayList<>();
   animals.add(new Animal());
   animals.add(new Animal());

   List<Pet> pets = new ArrayList<>();
   pets.add(new Pet());
   pets.add(new Pet());

   List<Cat> cats = new ArrayList<>();
   cats.add(new Cat());
   cats.add(new Cat());

   List<Dog> dogs = new ArrayList<>();
   dogs.add(new Dog());
   dogs.add(new Dog());

   iterateAnimals(animals);
   iterateAnimals(pets);
   iterateAnimals(cats);
   iterateAnimals(dogs);
}
Konsol çıktısı:
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Toplam 4 koleksiyon ve 8 nesne oluşturduk ve konsolda tam olarak 8 giriş var. Her şey harika çalışıyor! :) Joker karakter, belirli türlere bağlı gerekli mantığı tek bir yönteme kolayca sığdırmamızı sağladı. Her hayvan türü için ayrı bir yöntem yazma ihtiyacını ortadan kaldırdık. Uygulamamız bir hayvanat bahçesi veya bir veteriner tarafından kullanılsaydı ne kadar çok yönteme ihtiyaç duyacağımızı bir düşünün :) Ama şimdi farklı bir duruma bakalım. Kalıtım hiyerarşimiz değişmeden kalır: en üst düzey sınıf Animal, Pethemen altındaki sınıf ve bir sonraki düzeyde Catve sınıflardır. Şimdi yöntemi köpekler hariç her tür hayvanla çalışacak şekilde Dogyeniden yazmanız gerekiyor . Yani kabul etmeli ,iterateAnimals()Collection<Animal>Collection<Pet>veya Collection<Car>ile çalışmamalıdır Collection<Dog>. Bunu nasıl başarabiliriz? Görünüşe göre yine her tür için ayrı bir yöntem yazma ihtimaliyle karşı karşıyayız :/ Derleyiciye ne olmasını istediğimizi başka nasıl açıklayabiliriz? Aslında oldukça basit! Bir kez daha joker karakterler burada yardımımıza koşuyor. Ancak bu kez başka bir tür joker karakter kullanacağız — alt sınırlı bir joker karakter , super kullanılarak ifade edilir .
public static void iterateAnimals(Collection<? super Cat> animals) {

   for(int i = 0; i < animals.size(); i++) {

       System.out.println("Another iteration in the loop!");
   }
}
Burada prensip benzerdir. Yapı, <? super Cat>derleyiciye, yöntemin iterateAnimals()girdi olarak bir nesneler koleksiyonunu Catveya sınıfın herhangi bir atasını Catgirdi olarak kabul edebileceğini söyler. Bu durumda, Catsınıfın ebeveyni Petve ebeveyninin ebeveyni olan sınıfın Animaltümü bu açıklamayla eşleşir. Sınıf Dog, kısıtlamamızla eşleşmiyor, bu nedenle yöntemi bir List<Dog>bağımsız değişkenle kullanma girişimi bir derleme hatasıyla sonuçlanacak:
public static void main(String[] args) {

   List<Animal> animals = new ArrayList<>();
   animals.add(new Animal());
   animals.add(new Animal());

   List<Pet> pets = new ArrayList<>();
   pets.add(new Pet());
   pets.add(new Pet());

   List<Cat> cats = new ArrayList<>();
   cats.add(new Cat());
   cats.add(new Cat());

   List<Dog> dogs = new ArrayList<>();
   dogs.add(new Dog());
   dogs.add(new Dog());

   iterateAnimals(animals);
   iterateAnimals(pets);
   iterateAnimals(cats);

   // Compilation error!
   iterateAnimals(dogs);
}
Sorunumuzu çözdük ve joker karakterler bir kez daha son derece faydalı oldu :) Bununla birlikte ders sona erdi. Artık jeneriklerin Java çalışmanızda ne kadar önemli olduğunu görüyorsunuz — onlar hakkında tam 4 dersimiz oldu! Ama artık konuya iyice hakim oldunuz ve iş görüşmelerinde yeteneklerinizi kanıtlayabilirsiniz :) Ve şimdi görevlere geri dönme zamanı! Çalışmalarınızda başarılar! :)
Yorumlar
  • Popüler
  • Yeni
  • Eskimiş
Yorum bırakmak için giriş yapmalısınız
Bu sayfada henüz yorum yok