调用泛型类型的构造函数

时间:2012-02-20 18:06:34

标签: java 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);
    }
}

我不明白为什么我不能使用泛型来调用构造函数:

public class Box <T extends Item>
{
    T item;
    public Box()
    {
        item=new T(); // here I get the error
    }
}

我知道有可能有一个没有构造函数的类型,但这种情况是不可能的,因为Pencil有没有参数的构造函数,而Item是抽象的。 但是我从eclipse中得到了这个错误: 无法实现类型T
我不明白为什么,以及如何避免这种情况?

6 个答案:

答案 0 :(得分:13)

这是因为Java使用擦除来实现泛型,请参阅:

引用上述维基百科文章中的相关部分:

  

在编译时检查泛型的类型正确性。然后在称为类型擦除的过程中移除泛型类型信息。

     

由于类型擦除,无法在运行时确定类型参数。

     

因此,实例化参数化类型的Java类是不可能的,因为实例化需要调用构造函数,如果类型未知,则该构造函数不可用。

你可以通过自己提供课程来解决这个问题。这在这里有很好的解释:

答案 1 :(得分:11)

无法使用Java类型系统强制类层次结构具有其子类构造函数的统一签名。

考虑:

public class ColorPencil extends Pencil
{
    private Color color;

    public ColorPencil(Color color)
    {
        super();
        this.color=color;
    }   
}

这使得ColorPencil成为有效的T(它扩展了Item)。但是,此类型没有no-arg构造函数。因此,T()是荒谬的。

要做你想做的事,你需要使用反射。您无法从编译时错误检查中受益。

答案 2 :(得分:1)

T是您的类将处理的实际类型的别名,例如,如果您实例化Box<Item>,那么T实际上只是Item的别名。当您声明T extends Item时,您就会知道T至少具有与Item相同的界面,因此您可以将其视为一个。

我认为你真正想做的不是在item中实例化Box字段,而是实现一些方法让你操作该字段。

public class Box<T extends Item> {
    private T item;

    public T getItem() {
        return this.item;
    }

    public void setItem(T item) {
        return this.item = item;
    }
}

答案 3 :(得分:0)

因为在运行时T的类型是未知的。

答案 4 :(得分:0)

使用T来调用构造函数是不可能的,因为如果它可能比编译后可能会得到这样的代码:

public class Box{
    Object item;
    public Box(){
        item = new Object();
    }
}

因此,如果您使用此代码并传递一些对象,而不是您期望的某些特定类型的构造函数被调用,而是获得Object构造函数。

答案 5 :(得分:0)

您可以放置​​一个抽象方法,以便实现类可以确定如何构造新对象。

public abstract T constructT();

而不是调用

T t = new T()

你会打电话给

T t = constructT();

在您的实施调用中,它将创建为:

new Box<Integer>() {
    public Integer constructT(){ return new Integer(); }
}