W przeciwieństwie do .NET Java generics są implementowane za pomocą techniki zwanej "type erasure".
Oznacza to, że kompilator będzie używał informacji o typie podczas generowania plików klas, ale nie będzie przekazywał tych informacji do kodu bajtowego. Jeśli spojrzysz na skompilowane klasy za pomocą javap lub podobnych narzędzi, okaże się, że List<String>
jest prosty List
(z Object
) w pliku klasy, tak jak był w kodzie przed-Java-5.
Kod uzyskujący dostęp do ogólnej listy zostanie "przepisany" przez kompilator w celu uwzględnienia rzutów, które należałoby napisać we wcześniejszych wersjach. W efekcie dwa następujące fragmenty kodu są identyczne z punktu widzenia kodu bajtowego, gdy kompilator jest z nimi zrobić:
Java 5:
List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);
Java 1.4 i wcześniej:
List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);
Podczas czytania wartości z klasy ogólnej w Javie 5 konieczne rzutowanie do zadeklarowanego parametru typu jest wstawiane automatycznie. Podczas wstawiania kompilator sprawdzi wartość, którą próbujesz umieścić i przerwie z błędem, jeśli nie jest to String.
Podjęto wszelkie starania, aby stare biblioteki i nowy generowany kod były interoperacyjne bez potrzeby rekompilacji istniejących bibliotek. Jest to główna zaleta w stosunku do metody .NET, gdzie klasy ogólne i nietypowe sąsiadują ze sobą, ale nie mogą być swobodnie wymieniane.
Obie metody mają swoje wady i zalety, ale tak właśnie jest w Javie.
Aby wrócić do pierwotnego pytania: Nie można uzyskać informacji o typie w czasie wykonywania, ponieważ po prostu już go nie ma, po wykonaniu kompilatora. Jest to z pewnością ograniczone pod pewnymi względami i istnieją pewne marne sposoby, które zwykle opierają się na przechowywaniu gdzieś instancji klasy, ale nie jest to standardowa funkcja.
Chęć zrobienia tego jest niemal gwarancją zły projekt wybór. Istnieje duże prawdopodobieństwo, że instrukcja if wymaga znajomości każdego "typu" w celu implementacji, więc prawdopodobnie wszystkie te klasy powinny być tego samego typu, a "to zrobić" powinno być metodą wirtualną. Może to dotyczyć zawijania klas, ale ogólnie twój projekt poprawi się, jeśli pójdziesz tą drogą. –
Możliwości w instrukcjach if są przypadkami brzegowymi spośród wszystkich możliwych typów wywołań, które wymagają całkowicie odrębnych implementacji. Zgadzam się z tym, co tu mówisz, ale konkretna aplikacja to skała i ciężkie miejsce. –
Potrzeba uzyskania klasy dla parametru rodzajowego nie zawsze jest złą decyzją projektową. Jednym z uzasadnionych wymagań (moje! :) może być wywołanie metody, które wymaga parametru klasy <>. – dahvyd