调用generics类型的构造函数
如果我有这样的抽象类:
public abstract class Item { private Integer value; public Item() { value=new Integer(0); } public Item(Integer value) { this.value=new Integer(); } }
还有一些来自Item的类如下:
public class Pencil extends Item { public Pencil() { super(); } public Pencil(Integer value) { super(value); } }
我不明白为什么我不能使用generics调用构造函数:
public class Box { T item; public Box() { item=new T(); // here I get the error } }
我知道有可能有一个没有构造函数的类型,但这种情况是不可能的,因为Pencil有没有参数的构造函数,而Item是抽象的。 但是我从eclipse中得到了这个错误: 无法实现T型
我不明白为什么,以及如何避免这种情况?
无法使用Java类型系统来强制类层次结构具有其子类构造函数的统一签名。
考虑:
public class ColorPencil extends Pencil { private Color color; public ColorPencil(Color color) { super(); this.color=color; } }
这使得ColorPencil成为有效的T(它扩展了Item)。 但是,此类型没有no-arg构造函数。 因此,T()是荒谬的。
要做你想做的事,你需要使用reflection。 您无法从编译时错误检查中受益。
这是因为Java使用擦除来实现generics,请参阅:
引用上述维基百科文章中的相关部分:
在编译时检查generics的类型正确性。 然后在称为类型擦除的过程中移除generics类型信息。
由于类型擦除,无法在运行时确定类型参数。
因此,实例化参数化类型的Java类是不可能的,因为实例化需要调用构造函数,如果类型未知则该构造函数不可用。
您可以通过实际提供课程来解决这个问题。 这里有很好的解释:
- 在Java中创建generics类型的实例?
T
是您的类将处理的实际类型的别名,例如,如果您实例化Box
那么T
实际上只是Item
的别名。 当您声明T extends Item
您知道T
将至少具有与Item
相同的接口,因此您可以将其视为一个。
我认为你真正想做的不是实例化Box
的item
字段,而是实现一些方法来让你操作那个字段。
public class Box { private T item; public T getItem() { return this.item; } public void setItem(T item) { return this.item = item; } }
因为在运行时T的类型是未知的。
使用T来调用构造函数是不可能的,因为如果它可能比编译后可能会得到这样的代码:
public class Box{ Object item; public Box(){ item = new Object(); } }
因此,如果您使用此代码并传递一些对象而不是您期望的某些特定类型的构造函数被调用,而是您获得Object构造函数。
您可以放置一个抽象方法,以便实现类可以确定如何构造新对象。
public abstract T constructT();
而不是打电话
T t = new T()
你会打电话
T t = constructT();
在您的实施调用中,它将创建为:
new Box() { public Integer constructT(){ return new Integer(); } }