18 Ekim 2019 Cuma

Generics ve Lower Bounded Wildcard - "? super T" - Listeyi Doldurur

Giriş
<? super T> kuralını anlamak için PECS kuralını anlamak gerekir.
Açıklaması şöyle
Useful when defined as method argument where method implementation only writes data to collection
You can add only specified type of object and null to lower bounded collection.

PECS Kuralı
Kalıtım hiyerarşisinde üstten veya alttan sınırlandırılmış wildcard anlamına gelir. Java'daki kurallar PECS (Producer extends Consumer super) kuralı ile hatırlanabilir. Kural kısaca şu anlama geliyor.

1. Eğer liste dolaşılacaksa - yani producer ise - extends ile kullan.
2. Eğer listeye yeni bir şey eklenecekse - yani consumer ise - super ile kullan.
3. Eğer nesne girdi olarak kullanılıp yeni bir sonuç dönülecekse yani consumer ise - super - kullan.

Doldurmak İçin Tanımlama
Yukarıdaki PECS açıklamasından yola çıkarak listeye bir şey ekleneceğini anlayabiliriz. Liste şöyle tanımlanır.
List<? super Number> list = null;
Eklemek için Number'dan kalan bir sınıf kullanılabilir.

Okumak
Elimizde şöyle bir kod olsun.
ArrayList<? super A> listOfSuperA = new ArrayList<>();
Bu koddan sadece Object okuyabiliriz. Görmek için şöyle yaparız.
// invalid, because listOfSuperA could contain Objects, which are not convertible to A
A a2 = listOfSuperA.get(0); 

// valid, because whatever is in listOfSuperA, it can be converted to Object
aloObject o2 = listOfSuperA.get(0);
Comparator Örnekleri
Comparator nesneleri genellikle super ile tanımlanıyor. Açıklaması şöyle. Yani consumer bir nesne alır ve bir sonuç döner.
Comparator that we used in SortingService is a perfect example. This interface has one method that accepts a generic type and returns a concrete one. A typical example of a consumer. Other ones are Predicate, Consumer, Comparable, and many others from java.util package. Mostly all of these interfaces should be used with ? super T.
Örnek
Şöyle yaparız. Burada Comparator super ile kullanılıyor çünkü bir producer. Bir nesne alıp bir sonuç döndürüyor.
interface SortingService {
  <T> void sort(List<T> list, Comparator<? super T> comparator);
}

// universal comparator
Comparator<Employee> comparator = ...;

List<Manager> managers = ...;
List<Accountant> accountants = ...;
List<SoftwareEngineer> engineers = ...;

// All these examples compile successfullly
sortingService.sort(managers, comparator);
sortingService.sort(accountants, comparator);
sortingService.sort(engineers, comparator);
Map Örnekleri

Örnek
Map ArrayList alacak alacak diye tanımlanıyor. Object veya List eklemeye çalışmak hatadır
List<Object> list = new ArrayList();
Map<Object, ? super ArrayList> m = new HashMap<Object,  ArrayList>();
m.put(1, new Object()); //Error
m.put(2, list); //Error
Kullanmak için şöyle yapmak gerekir.
ArrayList list = new ArrayList();
Map<Object, ? super List> m = new HashMap<Object, List>(); 
m.put(2, list);
Liste Örnekleri

Örnek
Basit bir nesne hiyerarşimiz olsun. Shape sınıfının kendisi veya Shape sınıfından kalıtan Circle, Square, Rectangle gibi sınıflar listeye eklenebilir. Listeyi okumaya çalışmak hatalıdır.
public void testContraVariance(List<? super Shape> list) {
  list.add(new Shape());//compiles
  list.add(new Circle());//compiles
  list.add(new Square());//compiles
  list.add(new Rectangle());//compiles
  Shape shape= list.get(0); // does not compile
}
Örnek
Elimizde şöyle bir kod olsun. dest veri yapısına T'den kalıtan nesneler eklenebilir.
public class Collections {
  public static <T> void copy(List<? super T> dest, List<? extends T> src) {
      for (int i = 0; i < src.size(); i++)
        dest.set(i, src.get(i));
  }
}
Elimizde şöyle bir kod olsun
List<Animal> animals = new ArrayList<>();
List<Mammal> mammals = new ArrayList<>();
List<Cat> cats = ...
Şu kod derlenir.
Collections.copy(animals, mammals); // all mammals are animals
Collections.copy(mammals, cats);    // all cats are mammals
Collections.copy(animals, cats);    // all cats are animals
Collections.copy(cats, cats);       // all cats are cats 
Şu kod derlenmez.
Collections.copy(mammals, animals); // not all animals are mammals
Collections.copy(cats, mammals);    // not all mammals are cats
Collections.copy(cats, animals);    // mot all animals are cats

Hiç yorum yok:

Yorum Gönder