Jak mogę to osiągnąć?
public class GenericClass<T>
{
public Type getMyType()
{
//How do I return the type of T?
}
}
Wszystko, czego do tej pory próbowałem, zawsze zwraca typ, Object
a nie określony typ.
java
generics
reflection
Glenn
źródło
źródło
Odpowiedzi:
Jak wspomniano inni, jest to możliwe tylko poprzez refleksję w określonych okolicznościach.
Jeśli naprawdę potrzebujesz tego typu, jest to zwykły (bezpieczny dla typu) sposób obejścia:
źródło
Foo foo1 = GetDao<Foo>(Foo.class).get(Foo.class, 1)
public static <T> GenericClass<T> of(Class<T> type) {...}
, a następnie wywołać go jako takie:GenericClass<String> var = GenericClass.of(String.class)
. Trochę ładniej.Widziałem coś takiego
w hibernacji GenericDataAccessObjects Przykład
źródło
class A implements Comparable<String>
parametrze typu rzeczywistego jestString
, ale NIE MOŻE powiedzieć, że wSet<String> a = new TreeSet<String>()
parametrze typu rzeczywistego jestString
. W rzeczywistości informacje o parametrach typu są „usuwane” po kompilacji, jak wyjaśniono w innych odpowiedziach.java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
tę odpowiedź.Class-Mate
z pomocy ludzi z Jacksonów. Napisałem tutaj gist.github.com/yunspace/930d4d40a787a1f6a7d1(Class<T>) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()
aby uzyskać argumenty typu rzeczywistego.Generyczne nie są weryfikowane w czasie wykonywania. Oznacza to, że informacje nie są obecne w czasie wykonywania.
Dodanie generycznych składników do Javy przy jednoczesnym zachowaniu kompatybilności wstecznej było tour-de-force (możesz przeczytać o tym artykuł na ten temat: Zapewnienie bezpieczeństwa przeszłości: dodanie ogólności do języka programowania Java ).
Istnieje bogata literatura na ten temat, a niektórzy ludzie są niezadowoleni z obecnego stanu, niektórzy twierdzą, że tak naprawdę jest to przynęta i nie ma takiej potrzeby. Możesz przeczytać oba linki, uważam je za dość interesujące.
źródło
Użyj Guawy.
Jakiś czas temu napisałem kilka przykładów pełnym fledge tym abstrakcyjnych klas i podklas tutaj .
Uwaga: to wymaga instancji podklasy z
GenericClass
więc może wiązać parametru typu poprawnie. W przeciwnym razie po prostu zwróci typ jakoT
.źródło
java.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized
. Więc zmieniłem linięnew TypeToken(getClass()) { }
nanew TypeToken<T>(getClass()) { }
. Teraz kod działa poprawnie, ale Type to wciąż „T”. Zobacz: gist.github.com/m-manu/9cda9d8f9d53bead2035default Type getParameterType() { final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {}; final Type type = typeToken.getType(); return type; }
GenericClass
, powinieneś sprawić, aby ta klasaabstract
nie była użyta do niewłaściwego użycia.Oczywiście że możesz.
Java nie korzysta z tych informacji w czasie wykonywania, ze względu na kompatybilność wsteczną. Ale informacje są faktycznie obecne jako metadane i można uzyskać do nich dostęp poprzez odbicie (ale nadal nie są wykorzystywane do sprawdzania typu).
Z oficjalnego API:
http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29
Jednak w twoim scenariuszu nie użyłbym refleksji. Osobiście jestem bardziej skłonny do używania go do kodu frameworka. W twoim przypadku po prostu dodałbym ten typ jako parametr konstruktora.
źródło
Ogólnie rzecz biorąc, Java jest czasem kompilacji, co oznacza, że informacje o typie są tracone w czasie wykonywania.
zostanie skompilowany do czegoś podobnego
Aby uzyskać informacje o typie w czasie wykonywania, musisz dodać je jako argument ctor.
Przykład:
źródło
private final Class<T> type;
Type t = //String[]
źródło
Zastosowałem następujące podejście:
źródło
Nie sądzę, abyś mógł, podczas kompilacji Java używa wymazywania typu, aby twój kod był zgodny z aplikacjami i bibliotekami, które zostały utworzone przed generycznymi.
Z dokumentów Oracle:
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
źródło
Technika opisana w tym artykule przez Iana Robertsona działa dla mnie.
W skrócie szybki i brudny przykład:
źródło
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Myślę, że istnieje inne eleganckie rozwiązanie.
To, co chcesz zrobić, to (bezpiecznie) „przekazać” typ parametru typu ogólnego z klasy ukrytej do nadklasy.
Jeśli pozwolisz sobie myśleć o typie klasy jako o „metadanych” w klasie, sugeruje to metodę Java do kodowania metadanych w czasie wykonywania: adnotacje.
Najpierw zdefiniuj niestandardową adnotację według następujących linii:
Następnie możesz dodać adnotację do swojej podklasy.
Następnie możesz użyć tego kodu, aby uzyskać typ klasy w klasie podstawowej:
Niektóre ograniczenia tego podejścia to:
PassedGenericType
) podajesz w DWÓCH miejscach, a nie w jednym, który nie jest osuszony.źródło
To jest moje rozwiązanie:
źródło
Oto działające rozwiązanie !!!
UWAGI: Może być używany tylko jako nadklasa
1. Musi zostać rozszerzony o typ maszynowy (
Child extends Generic<Integer>
)LUB
2. Musi zostać utworzony jako anonimowa implementacja (
new Generic<Integer>() {};
)źródło
Nie możesz Jeśli dodasz zmienną składową typu T do klasy (nawet nie musisz jej inicjować), możesz użyć jej do odzyskania typu.
źródło
Oto jeden ze sposobów, z których musiałem skorzystać raz lub dwa:
Wraz z
źródło
Jedno proste rozwiązanie dla tej kabiny jest jak poniżej
źródło
Aby wypełnić niektóre odpowiedzi tutaj, musiałem uzyskać ParametrizedType MyGenericClass, bez względu na to, jak wysoka jest hierarchia, za pomocą rekurencji:
źródło
Oto moja sztuczka:
źródło
T
jest zmienną typu. W przypadku, gdyT
jest to zmienna typu, varargs tworzy tablicę usuwaniaT
. Zobacz np . Http://ideone.com/DIPNwd .Na wypadek, gdybyś użył funkcji przechowywania zmiennej przy użyciu typu ogólnego, możesz łatwo rozwiązać ten problem, dodając metodę getClassType w następujący sposób:
Używam podanego obiektu klasy później, aby sprawdzić, czy jest to instancja danej klasy, w następujący sposób:
źródło
value
jestnull
? Po drugie, co jeślivalue
jest podklasąT
?Constant<Number> c = new Constant<Number>(new Integer(0)); Class<Number> n = c.getClassType();
zwraca,Integer.class
kiedy powinien wrócićNumber.class
. Lepiej byłoby wrócićClass<? extends T>
.Integer.class
jest,Class<? extends Number>
ale nie jestClass<Number>
.Oto moje rozwiązanie
Niezależnie od tego, ile poziomów ma Twoja hierarchia klas, to rozwiązanie nadal działa, na przykład:
W takim przypadku getMyType () = java.lang.String
źródło
Exception in thread "main" java.lang.NullPointerException at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.<init>(Main.java:43) at Main.main(Main.java:61)
źródło
Oto moje rozwiązanie. Przykłady powinny to wyjaśniać. Jedynym wymaganiem jest to, że podklasa musi ustawić typ ogólny, a nie obiekt.
źródło
Zrobiłem to samo, co @Moesio Above, ale w Kotlin można to zrobić w ten sposób:
źródło
Może to być przydatne dla kogoś. Możesz użyć java.lang.ref.WeakReference; tą drogą:
źródło
WeakReference
? Podaj wyjaśnienie swojej odpowiedzi, a nie tylko kod.SomeClass<MyClass>
, możesz utworzyć instancjęSomeClass
i zadzwonićgetType
do tej instancji oraz mieć czas działaniaMyClass
.WeakReference
? To, co powiedziałeś, nie różni się od większości innych odpowiedzi.AtomicReference
,List
,Set
).Uznałem, że jest to proste, zrozumiałe i łatwe do wyjaśnienia rozwiązanie
źródło
(T...t)
. (Dlatego ten kod nie działa.)