Java: Create an object whose type is a type parameter
I want to write the equivalent Java code of a C# code.
My C# code is as follows:
public abstract class A<T> where T : A<T>, new()
{
public static void Process()
{
Process(new T());
}
public static void Process(T t)
{
// Do Something...
}
}
public class B : A<B>
{
}
public class C : A<C>
{
}
Java equivalent of my code looks like this.
public abstract class A<T extends A<T>>
{
public static <T extends A<T>> void process()
{
process(new T()); // Error: Cannot instantiate the type T
}
public static <T extends A<T>> void process(T t)
{
// Do Something...
}
public class B extends A<开发者_JAVA技巧B>
{
}
public class C extends A<C>
{
}
}
Here the "new()" syntax in class declaration forces derived classes to write a default constructer which makes possible to call "new T()" from base class. In other words when i am wrting the base class i am sure that the derived class will have a default constructer, so that i can instantiate a derived class object from base class.
My problem in Java is, I cannot instantiate a derived class object from super class. I get "Cannot instantiate the type T"
error for "new T()"
call. Is there any C# similar way in Java or should I use something like prototype pattern and cloning?
Java doesn't support reified generics, so there is no equivalent to "new T();
". The way I work around this is to use reflection against a type token. The type token indicates what the generic type is.
public abstract class A<T> {
private Class<T> typeToken;
// constructor
public A() {
typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
}
Then use reflection to instantiate the class. It's ugly, but it gets the job done.
You can find some explanation of the difference between generics in C# and Java from this li nk - comparing java and C# generics.
Java generics are a completely compile-time construct. You cannot do anything with generic type parameters that rely in any way on runtime information. This includes:
- Creating instances of generic type parameters.
- Creating arrays of generic type parameters.
- Quering the runtime class of a generic type parameter.
- Using instanceof with generic type parameters.
You can bypass this restriction with java.lang.reflect
namepsace. For example see this stackoverflow question: Genercs and Class.forName()
Also, beware of this if you are using generics.
T[] someArray = new T[];
This is one reason to prefer ArrayList
to arrays. The reason for the problem lies with reifiability and type erasure.
Just use the bog standard Abstract Factory pattern. You then get the additional benefits that you are not tying down to a specific type, the implementation type need not have a specific constructor, the instance can have some parameterisation, instances can be cached, etc., etc.
For the love of god, don't use reflection.
In addition to the other comments, I would suggest not using generics. They are not needed--they get stripped out at compile time anyway--and if you do not know them well you will try to make them do things they cannot.
Once you have your class working properly, then add them back in. Your IDE will, at that point, give you a lot of useful and intelligible advice, and the generics will warn you when you use objects of the wrong class.
It does look possible to me that this class will not need generics at all when finished. (I don't know what else this class may do, and I do not understand the use of the static methods--they will never have access to an individual instance's type information.)
Actually this is not a problem in Java. The idiom is passing the class
public static <T extends A<T>> T process(Class<T> clazz)
{
T o = clazz.newInstance();
process( o );
return o;
}
X x = process(X.class); // not too verbose
I added a return value to illustrate the general case.
精彩评论