Zazwyczaj widziałem, jak ludzie używają literału klasowego w następujący sposób:
Class<Foo> cls = Foo.class;
Ale co, jeśli typ jest ogólny, np. Lista? Działa to dobrze, ale ma ostrzeżenie, ponieważ Listę należy sparametryzować:
Class<List> cls = List.class
Dlaczego więc nie dodać <?>
? To powoduje błąd niedopasowania typu:
Class<List<?>> cls = List.class
Pomyślałem, że coś takiego będzie działać, ale jest to zwykły błąd składniowy:
Class<List<Foo>> cls = List<Foo>.class
Jak mogę uzyskać statystyki Class<List<Foo>>
, np. Używając literału klasowego?
I mógłby użyć @SuppressWarnings("unchecked")
, aby pozbyć się ostrzeżeń wywołanych przez nie-parametrycznego wykorzystaniem listy w pierwszym przykładzie Class<List> cls = List.class
, ale raczej nie.
Jakieś sugestie?
List<Integer> list1 = new ArrayList<Integer>(); List<String> list2 = (List<String>)list1; list2.add("foo"); // perfectly legal
Możesz; t to zrobić w Javie, pojawia się błąd kompilacji niezgodności typów!List<String> list2 = (List<String>) (Object) list1;
Brak literałów klas dla sparametryzowanych typów, jednak istnieją obiekty Type, które poprawnie definiują te typy.
Zobacz java.lang.reflect.ParameterizedType - http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/ParameterizedType.html
Biblioteka Google Gson definiuje klasę TypeToken, która pozwala po prostu generować sparametryzowane typy i używa jej do określania obiektów json ze złożonymi sparametryzowanymi typami w ogólny przyjazny sposób. W twoim przykładzie użyłbyś:
Zamierzałem publikować linki do javadoc klas TypeToken i Gson, ale przepełnienie stosu nie pozwoli mi opublikować więcej niż jednego linku, ponieważ jestem nowym użytkownikiem, można je łatwo znaleźć za pomocą wyszukiwarki Google
źródło
clzz = new TypeToken<E>(){}.getRawType();
do późniejszej iteracji podobnie wyliczonych wyliczeń,clzz.getEnumConstants()
a następnie użyć refection, aby nazwać metody członkowskieMethod method = clzz.getDeclaredMethod("getSomeFoo");
wygraną! Dziękuję Ci!Możesz nim zarządzać za pomocą podwójnej obsady:
@SuppressWarnings("unchecked") Class<List<Foo>> cls = (Class<List<Foo>>)(Object)List.class
źródło
Object
naClass
, prawdopodobnie możesz zaoszczędzić na narzutach (bezcelowego) sprawdzonego rzutu.Class
zamiastObject
, jak sugerujesz, wydaje się bardziej znaczące, ale nie usuwa potrzeby@SuppressWarnings("unchecked")
adnotacji, dodaje nawet nowe ostrzeżenie:Class is a raw type. References to generic type Class<T> should be parameterized
Class<?>
:(Class<List<Foo>>)(Class<?>)List.class
unchecked
ostrzeżenie. Ta odpowiedź nic nie zmienia / nie poprawia. OP nawet stwierdza w swoim pytaniu, że nie chce używaćSuppressWarnings
...Aby wyjaśnić odpowiedź Cletusa, w czasie wykonywania usuwany jest cały zapis typów ogólnych. Generyczne są przetwarzane tylko w kompilatorze i służą do zapewnienia dodatkowego bezpieczeństwa typu. Są to tak naprawdę tylko stenogramy, które pozwalają kompilatorowi wstawiać typecasty w odpowiednich miejscach. Na przykład wcześniej trzeba wykonać następujące czynności:
staje się
Pozwala to kompilatorowi sprawdzić kod w czasie kompilacji, ale w czasie wykonywania nadal wygląda jak pierwszy przykład.
źródło
Java Generics Pytania i dlatego też Cletus' odpowiedź brzmi jak nie ma sensu mając
Class<List<T>>
jednak prawdziwym problemem jest to, że jest to bardzo niebezpieczne:W
cast()
sprawia, że wygląda tak, jakby to bezpieczne, ale w rzeczywistości tak nie jest bezpieczny w ogóle.Chociaż nie rozumiem, gdzie nie może być
List<?>.class
=,Class<List<?>>
ponieważ byłoby to bardzo pomocne, gdy masz metodę, która określa typ na podstawie ogólnego typuClass
argumentu.Dla
getClass()
istnieje JDK-6184881 prośbą, aby przełączyć się za pomocą symboli wieloznacznych, jednak nie wygląda jak ta zmiana zostanie przeprowadzone (bardzo szybko), ponieważ nie jest kompatybilny z poprzedniego kodu (patrz ten komentarz ).źródło
Jak wszyscy wiemy, to się kasuje. Ale może być znany w pewnych okolicznościach, w których typ jest wyraźnie wymieniony w hierarchii klas:
A teraz możesz robić takie rzeczy jak:
Więcej informacji tutaj . Ale znowu prawie niemożliwe jest odzyskanie:
gdzie zostaje skasowany.
źródło
GenericEntity
aGenericType
.Ze względu na ujawniony fakt, że literały klasowe nie zawierają ogólnych informacji o typie, myślę, że powinieneś założyć, że nie będzie można pozbyć się wszystkich ostrzeżeń. W pewien sposób użycie
Class<Something>
jest takie samo, jak użycie kolekcji bez określania typu ogólnego. Najlepsze, co mogłem wymyślić, to:źródło
Możesz użyć metody pomocnika, aby pozbyć się
@SuppressWarnings("unchecked")
całej klasy.Wtedy mógłbyś pisać
Inne przykłady użycia to
Ponieważ jednak rzadko kiedy jest to naprawdę przydatne, a użycie metody nie pozwala na sprawdzenie typu kompilatora, nie zalecałbym implementowania go w miejscu, gdzie jest publicznie dostępny.
źródło