9 Haziran 2020 Salı

Type Erasure

Giriş
Type erasure kod derlendikten sonra generic parametrenin tipinin kaybedilip başka bir şey haline gelmesidir. Açıklaması şöyle. Tipin kaybedilmemesi kavramı Reified Generics. Bu kavram şu anda Java'da yok
On runtime there are no type checkings in collections

Örnek
Elimizde şöyle bir kod olsun.
public static <T> T handle(T val) {
  System.out.println("T");
  return val;
}

public static <T extends String> T handle(T val) {
  System.out.println("T extends String");
  return val;
}
Kod derlendikten sonra şu hale gelir.
public static Object handle(Object val) {
  System.out.println("T");
  return val;
}

public static String handle(String val) {
  System.out.println("T extends String");
  return val;
}
Örnek - ClassCastException 
Elimizde şöyle bir kod olsun. stringList generic olmadığı için farklı tipte nesneler eklenebiliyor.

m1 metodu Iterator<Object> haline geldiği için System.out.println(Object) metodunu çağırır ve sorun çıkmaz.

Ancak m2() metodu ClassCastException fırlatır. Çünkü Iterator<Object> haline gelse bile System.out.println(String) metodunu çağırır ve exception alırız.
public static void main(String[] args) {
  ArrayList stringList = new ArrayList();
  stringList.add(new Employee(1,"A"));
  stringList.add(new Employee(2,"j"));
  stringList.add(new Employee(3,"d"));
  stringList.add("Hello");
  stringList.add(new String("Abc"));
  stringList.add(10);
  stringList.add(new Integer(100));

  System.out.println(stringList);

  m1(stringList);
  m2(stringList);

}

public static void m1(ArrayList<Employee> al){
  Iterator<Employee> iterator = al.iterator();
  while(iterator.hasNext()){
    System.out.println(iterator.next());
  }
}

public static void m2(ArrayList<String> al){
  Iterator<String> iterator = al.iterator();
  while(iterator.hasNext()){
    System.out.println(iterator.next());
  }
}
Örnek - Derleme Hatası
Şu kod type erasure yüzünden derlenmez. Aslında amaç bazı Class tipinin kodlanmamasını sağlamak.
public class Publisher<T> {

  private static final Class[] SUPPORTED_CLASSES = new Class[]{T1.class, T2.class};

  public Publisher() {
    if(Arrays.asList(SUPPORTED_CLASSES).contains(T)) { // error: expression expected!
      System.out.println("Class not supported!");
    }
  }
}
Çünkü T'nin tipi çalışma esnasında yoktur. Yani
new Publisher<T1>
ile
new Publisher<T2>
arasındaki farkı kaybederiz.

Çözüm
Düzeltmek için şöyle yaparız.
public Publisher(Class<T> clazz) {
  if(!SUPPORTED_CLASSES.contains(clazz)) {
    System.out.println("Class not supported!");
  }
}
Çözüm
Şöyle yaparız. Böylece sadece MyInterface'ten kalıtan sınıflar derlenebilir.
public class Publisher<T extends S, MyInterface>

Hiç yorum yok:

Yorum Gönder