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?

luvieere
  • 37,065
  • 18
  • 127
  • 179

3 Answers3

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).

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • 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. – luvieere Jun 16 '11 at 14:58
  • 1
    @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. – C. K. Young Jun 16 '11 at 14:59
  • SomeClass has a radically different behavior than SomeClass. How would this be addressed by using SomeClass>? – luvieere Jun 16 '11 at 15:04
  • 1
    @luvieere: In Java, at runtime `SomeClass` is the same type as `SomeClass`: 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.) – C. K. Young Jun 16 '11 at 15:07
  • @luvieere: In other words, `SomeClass` is _not_ "radically different" from `SomeClass`. – C. K. Young Jun 16 '11 at 15:08
  • 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 makes all the difference. – luvieere Jun 16 '11 at 15:48
  • @luvieere: It doesn't make a difference. Trust me. :-) For example, if you're dealing with a `List`, 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. – C. K. Young Jun 16 '11 at 15:57
  • @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. – C. K. Young Jun 16 '11 at 15:58
  • "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. – luvieere Jun 16 '11 at 17:59
  • @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). – C. K. Young Jun 16 '11 at 18:07
  • 1
    I managed to rewrite my code not to rely on the type's names anymore and now, indeed, the instantiation works without hassle. – luvieere Jun 30 '11 at 11:49
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

fmucar
  • 14,361
  • 2
  • 45
  • 50
1

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

Waldheinz
  • 10,399
  • 3
  • 31
  • 61