4 Nisan 2019 Perşembe

Generic ve Unbounded Wildcard - Heterogeneous Container

Giriş
Sadece ? karakterinin kullanılması anlamına gelir. Açıklaması şöyle
In generics ? (called as unbounded wildcard) is used to accept just any type of object.
Upper-bound is when you specify (? extends Field) means argument can be any Field or subclass of Field.
Lower-bound is when you specify (? super Field) means argument can be any Field or superclass of Field.
Açıklaması şöyle. Yani Object sınıfına ait metodlar kullanılabilir.
Use it as method argument when your method implementation does not want to know what type of objects are present in collection. It means you are just using object class methods or collections generic methods like clear(), size() and toString(). You can not add or read elements from unbounded collection except null.

1. Tanımlama
Şöyle yaparız
List<?> raw = new ArrayList<String>();
2. Ekleme Yapma
Bu listeye sadece null eklenebilir. Başka bir nesne eklenemez. Açıklaması şöyle.
Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
Örnek
Elimizde şöyle bit kod olsun.
Collection fromRealm(String realmName) {...}
Bu kodu Unbounded Wildcard kullanan Collection haline getirmek ekleme işlemini bozabileceği için yapılmayabilir.

3. Unbounded Wildcard Kullanan Collection ve Kullanmayan Collection Farkı
Açıklaması şöyle.
The major difference between raw type and unbounded wildcard <?> is that the latter is type safe, that is, on a compile level, it checks whether the items in the collection are of the same type. Compiler won't allow you to add string and integer to the collection of wildcard type, but it will allow you to do this:
Örnek
Wildcard kullanmayan Collection nesnesine şöyle yapabiliriz.
List raw = new ArrayList();
raw.add("");
raw.add(1);
4. Typesafe Heterogeneous Container
Genellikle ortak Class<?> olarak kullanılır. Joshua Bloch'un Effective Java kitabında anlatılıyor. Buna aynı zamanda Class To Instance X demek te mümkün. Mesela ClassToInstaceMap diyebiliriz.

Örnek - ClassToInstaceMap 
Şöyle yaparız. Burada key Class<?> ve Value ise bu class tipinden bir nesne. Value nesnesi klass.cast() metodu ile cast edilir.
public class Favorites {
  private Map<Class<?>, Object> favorites =  new HashMap<Class<?>, Object>();

  public <T> void setFavorite(Class<T> klass, T thing) {
    favorites.put(klass, thing);
  }

  public <T> T getFavorite(Class<T> klass) {
    return klass.cast(favorites.get(klass));
  }

  public static void main(String[] args) {
    Favorites f = new Favorites();
    f.setFavorite(String.class, "Java");
    f.setFavorite(Integer.class, 0xcafebabe);
    String s = f.getFavorite(String.class);
    int i = f.getFavorite(Integer.class);
  }
}
Örnek
Elimizde şöyle bir kod olsun.
public interface ElementFactory<T> {
  T build(Document document, XPATHHidaValues xpathHidaValues) throws Exception;
}
Şöyle yaparız. Burada Key yine Class<?> ,Value ise bu sefer Object değil bir arayüz. Arayüzümüz generic. Ancak arayüzümüz sadece generic T tipi dönüyor. Parametre tipleri ise sabit.
public class ElementFactoryRegistry {

  private static Map<Class<?>, ElementFactory<?>> elementBuilder = new HashMap<>();

  static {
    elementBuilder.put(Schreibsprache.class, new SchreibSpracheFactory());
    elementBuilder.put(Material.class, new MaterialListFactory());
    elementBuilder.put(Abmessungen.class, new AbmessungFactory());
    elementBuilder.put(Format.class, new FormatFactory());
    elementBuilder.put(Umfang.class, new UmfangFactory());
    elementBuilder.put(Schrift.class, new SchriftenListFactory());
  }

  public static <T> T buildElement(Type targetType, Document document,
      XPATHHidaValues xpathHidaValues)
      throws Exception {

    if (!elementBuilder.containsKey(targetType)) {
      throw new IllegalArgumentException("Missing Element Factory for Type "+targetType);
    }
    return (T) elementBuilder.get(targetType).build(document, xpathHidaValues);
  }
}
Örnek
Bu en karışık örnek. Elimizde şöyle bir kod olsun.
public class MyPublisher<E extends EventObject, L extends EventListener> {

  protected List<L> listeners;
  public abstract void publish (E e);

  public void addListener(L listener){
    list.add(listener);
  }
}

Foo sınıfımız şöyle bir kod olsun.
FooEvent sınıfı EventObject sınıfında kalıtsın.
FooEventEventListener arayüzü EventListener'dan kalıtsın  ve onFooEvent() metodu olsun
public class FooPublisher extends MyPublisher<FooEvent, FooEventEventListener> {

  public void publish(FooEvent e){
    for (FooPublisher<FooEvent,FooListener> l = listeners){
      l.onFooEvent(e);
    }
  }
}
Container sınıfını şöyle tanımlarız. Burada MyPublisher için EventObject ve EventListener tipini belirtmiyoruz.
Map<Class<?>, MyPublisher<?, ?>> elementBuilder = ...
register metodu şöyle olur. Burada map'ten elde ettiğimiz nesneyi parametre olarak verdiğimi listener tipine cast etmek zorunda kaldık.
public class PublisherContainer {

  public <L extends EventListener> void register(Class<?> clazz, L eventListener){
    MyPublisher<?,L> publisher = (MyPublisher<?,L>)map.get(clazz);
    publisher.add(eventListener);
    }
  }
}
publish metodu şöyle olur. Burada map'ten elde ettiğimiz nesneyi EventObject tipine cast etmek zorunda kaldık.
public class PublisherContainer {

  public void publish(EventObject e){
    MyPublisher<EventObject,?> publisher =
      (MyPublisher<EventObject,?>)map.get(e.getClass());
    publisher.publish(e);
    }
  }
}



Hiç yorum yok:

Yorum Gönder