Cause generics in Java 1.5 and 1.6 are implemented using erasure, in most cases you can not get class object for type parameter, which means that in your generic classes you can not instantiate objects of type parameters. For example, the following code will not compile:
class Foo<T> { T field; public void bar() { field = new T(); // error } }
You have to implement it like this:
class Foo<T> { T field; public void bar(Class<T> clazz) { field = clazz.newInstance()); } }
Of course, we assume that there exists a default constructor for T class. Otherwise you would need to find the constructor using java.lang.reflect API.
One way or the other, it is not too elegant. Fortunately, you can avoid such ugly code in some situations. In case where your class is a subclass of fully parameterized type you could get classes of actual type arguments using the Reflect API. For example:
class Mona extends Foo<Long> { }
Objects of Mona class can use the Reflect API to create instances of Long, which is a type parameter of Foo class extended by Mona. A method, which finds class of the type parameter and creates its instance, can look like this:
abstract class Foo<T> { private Class<T> tClass; T field; public void bar(Class<T> clazz) { Type type = getClass().getGenericSuperclass(); if (type instanceof ParameterizedType) { ParameterizedType paramType = (ParameterizedType)type; tClass = (Class<T>) paramType.getActualTypeArguments()[0]; field = tClass.newInstance(); } } } final class Mona extends Foo<Long> { }
Why classes are abstract and final? Because it’s the only case when the presented approach will work.
- Why abstract: only instances of subclasses of parametrized Foo class will get ParameterizedType by
getClass().getGenericSuperclass()
, so you can not use Foo directly and there always must be some class in the type hierarchy which extends fully parametrized Foo (here we use Mona class for this). - Why final: you have to call
getClass().getGenericSuperclass()
on direct subclass of the generic class. For instances of subclasses of Mona you would needgetClass().getSuperclass().getGenericSuperclass()
. Of course, you can callgetClass().getSuperclass()
andgetClass().getGenericSuperclass()
in a loop until you get ParameterizedType.
This pattern is frequently used for generic DAO classes.
A better way is to require a general Factory, which is what a Constructor would be if it wasn’t so tightly bound to the implementation of objects/classes in Java.
Then you just take a generic Factory, and call newInstance.
public [T] void doSomething(Factory[T] factory)
{
T t=factory.newInstance();
t.stuff();
}
I used [] to avoid HTML swallowing, as there’s no Preview button.
You should really be able to do T.getClass()
We have to wait for Java 7 for that.
Yeah, reified generics hopefully will be part of Java 7 – see http://tech.puredanger.com/java7#reified for some more info.
thx for all comments.
btw, I have fixed some formatting issues which arouse with new web template.
“Fortunately, you can avoid such ugly code in some situations. In case where your class is a subclass of fully parameterized type you could get classes of actual type arguments using the Reflect API.”
How much is real?
Nice solution.
Though I don’t get one thing.
If I have a generic container FooContainer of Foo.
Where is in fact Foo.
How can FooContainer create an instance of ?
Nice solution.
Though I don’t get one thing.
If I have a generic container FooContainer of Foo.
Where is in fact Foo.
How can FooContainer create an instance of ?
html… :(
Nice solution.
Though I don’t get one thing.
If I have a generic container FooContainer[C] of Foo[T].
Where [C] is in fact Foo[T].
How can FooContainer create an instance of [C]?
A nice article which shows how to extend this approach to allow using reflection with longer class hierarchies: http://www.artima.com/weblogs/viewpost.jsp?thread=208860
@Pim: This article answers your question