Use reflection to create a generic parameterized class in Java
Asked Answered
V

3

9

How can I use reflection to create a generic parameterized class in Java?

I have

public class SomeClass<T> {
   public SomeClass<T>() {
   }
}

and I need an instance of it.

I've tried variations of

Class c = Class.forName("SomeClass");

but could not find a syntax that would allow me to get an appropriately typed instance, like, say

SomeType instance = (SomeType)Class.forName("SomeClass<SomeType>").createInstance();

So, how could I go about doing this?

Vibration answered 16/6, 2011 at 14:45 Comment(0)
A
9

Java uses erasure-based generics (i.e., the type parameters are erased at runtime—for example, List<Integer> and List<String> are treated as the same type at runtime). Since reflection is inherently a runtime feature, the type parameters are not used or involved at all.

In other words, you can only instantiate the raw type (SomeClass, not SomeClass<T>) when you're using reflection. You will then have to manually cast the type to the generic version (and generate an unchecked warning).

Altamira answered 16/6, 2011 at 14:48 Comment(11)
I can't manually cast the type to the generic version, as I know the type only by its string name. This is why I need a means of obtaining a correctly-typed instance without knowing more than the types' names as Strings.Vibration
@luvieere: Then just use SomeClass<?> in your source code. The type parameter is ever only useful at compile-time, and since you don't have that info at compile-time, ? is the way to express that.Altamira
SomeClass<Type1> has a radically different behavior than SomeClass<Type2>. How would this be addressed by using SomeClass<?>?Vibration
@luvieere: In Java, at runtime SomeClass<Type1> is the same type as SomeClass<Type2>: both are of type SomeClass. That is why the kinds of things you can do with type parameters in Java is very restricted compared to what you can do in, say, C#. (Java == erasure generics, i.e., type parameters lost at runtime. C# == reified generics, i.e., type parameters preserved at runtime.)Altamira
@luvieere: In other words, SomeClass<Type1> is not "radically different" from SomeClass<Type2>.Altamira
SomeClass in my case is an Android class derived from BaseAdapter, and the parameter type is quite relevant, as different types return different List item resources. So I'm quite confident that the T in SomeClass<T> makes all the difference.Vibration
@luvieere: It doesn't make a difference. Trust me. :-) For example, if you're dealing with a List<String>, its get() method returns a String; a List<?>'s get() method returns an Object, which you have to cast to String yourself. In both cases, the generated bytecode would be identical.Altamira
@luvieere: In other words, if you use SomeClass<?>, the most you have to do is throw in a few extra casts. It won't change the behaviour of the code any.Altamira
"the most you have to do is throw in a few extra casts" - please understand that I cannot rely on casts. I do not know the types needed inside the instantiating class, I need the created instance to be of the exact type by only using types' names, provided at runtime.Vibration
@luvieere: You'll need to pastebin some real code that demonstrates what you're trying to do. I'll then pastebin back some real code that actually does it (if it's actually achievable).Altamira
I managed to rewrite my code not to rely on the type's names anymore and now, indeed, the instantiation works without hassle.Vibration
S
2

See/search for "Type erasure". Generics are for compile time and they are not availble at runtime so what you are trying is not possible. You need to use the raw type for reflection

Stoned answered 16/6, 2011 at 14:49 Comment(0)
S
1

Because of type erasure, at runtime SomeClass is all there is left of SomeClass<SomeType>.

Snowonthemountain answered 16/6, 2011 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.