If I have an abstract class like this:
public abstract class Item
{
private Integer value;
public Item()
{
value=new Integer(0);
}
It's impossible to use T to call a constructor because if it would be possible than after a compilation you would get the code like this:
public class Box{
Object item;
public Box(){
item = new Object();
}
}
So if you would use this code and pass some object than you expect that there is the constructor of some specific type is called, but instead you get the Object constructor.
This is because Java uses erasure to implement generics, see this:
To quote the relevant parts from the above Wikipedia article:
Generics are checked at compile-time for type-correctness. The generic type information is then removed in a process called type erasure.
As a result of type erasure, type parameters cannot be determined at run-time.
Consequently, instantiating a Java class of a parameterized type is impossible because instantiation requires a call to a constructor, which is unavailable if the type is unknown.
You can go around this by actually providing the class yourself. This is well explained here:
T is an alias for the actual type your class will handle, for example if you instantiate Box<Item> then T is really just an alias for Item. As you declare T extends Item then you know that T will have at least the same interface as Item, so you can treat it like one.
I think what you really want to do is not instantiate the item field in Box, but instead implement a couple of methods to let you manipulate that field.
public class Box<T extends Item> {
private T item;
public T getItem() {
return this.item;
}
public void setItem(T item) {
return this.item = item;
}
}
There is no way to use the Java type system to enforce that a class hierarchy has a uniform signature for the constructors of its subclasses.
Consider:
public class ColorPencil extends Pencil
{
private Color color;
public ColorPencil(Color color)
{
super();
this.color=color;
}
}
This makes ColorPencil a valid T (it extends Item). However, there is no no-arg constructor for this type. Hence, T() is nonsensical.
To do what you want, you need to use reflection. You can't benefit from compile-time error checking.
You can place an abstract method so that the implementing class can determine how to construct the new object.
public abstract T constructT();
and instead of calling
T t = new T()
you would call
T t = constructT();
On your implementing call it would be created as:
new Box<Integer>() {
public Integer constructT(){ return new Integer(); }
}
Because at runtime the type of T is unknown.