Generics sind eine feine Sache die in nahezu jeder Application anwendung finden. Die meisten Entwickler werden jedoch festgestellt haben das die generische Typinformation zur Laufzeit nicht mehr zur Verfügung stehen. Aber wie dann zur Laufzeit an den Typ gelangen?
“Type Erasure” heißt das “Phänomen” das aus abwärtskompatiblen Gründen fester Bestandteil des Java Compilers ist. Generische Informationen sind somit nur zur Compile-Zeit vorhanden und werden bei der Übersetzung in den ByteCode entfernt. Damit fällt eine Factory wir die folgende erst einmal weg:
public class Factory<T> { public T create() { return new T(); // Type-Erasure in Action }
Wir können natürlich nun die konkrete Klasse als zusätzlichen Parameter in eine solche Factory übergeben um auf Basis dieser neue Instanzen zu erzeugen. Das funktioniert, fühlt sich aber nach “doppeltem Aufwand” an, da die konkrete Klasse zwei mal angegeben wird.
Ein kleine Schlupfloch gibt es aber: anonyme Klassen. Anders als “normale” Klassen sind bei anonymen Klassen die generischen Informationen auch zur Laufzeit vorhanden.
In unserer Factory können wir dann per Reflection den generischen Typ ermitteln und damit z.B. eine entsprechende Instanz erzeugen.
public class Factory<T> { public T create() throws InstantiationException, IllegalAccessException { Type superClassType = this.getClass().getGenericSuperclass(); Type tType = ((ParameterizedType) superClassType).getActualTypeArguments()[0]; Class clazz = (Class) tType; return clazz.newInstance(); } }
//Type Erasure > Exception Customer c = new Factory<Customer>().create(); //anonyme Klasse Customer c = new Factory<Customer>(){}.create();