为什么我们可以创建通用模板的新实例而不是Java中的泛型类型?

时间:2014-07-19 11:15:18

标签: java generics

我知道无法做到: new T其中T由于类型擦除而属于泛型类型。

为什么可以这样做new A<T>,其中T是通用的?例如,为什么以下编译?

static class A<T>{
    T t;
    A(T t){
        this.t=t;
    }
}

static class B<T>{

    A<T> create(T t){
        return new A<T>(t);
    }
}

public static void main (String[] args) throws java.lang.Exception
{
    A<Integer> a = new B<Integer>().create(3);
}

3 个答案:

答案 0 :(得分:6)

因为A<Integer>在编译和运行时是一个定义良好的类型。

在概念上,中间步骤之后:

new B<Integer>()

您对.create(3)的致电等同于致电:

static class B {
    A<Integer> create(Integer t){
        return new A<Integer>(t);
    }
}
擦除后,A<Integer>变为A,这是一种有效的类型。

你不能new T因为T不是定义明确的类型,它只是一个标记。如果确实需要,可以使用以下内容获取相应的类并实例化T类型的对象:

public class GenericFactory {
    <T> T create(Class<T> c) throws Exception {
        return c.newInstance();
    }
}

并使用它:

new GenericFactory().create(Integer.class);
是的,那太丑了。

答案 1 :(得分:0)

由于类型擦除,您可以实例化new A<T>()。如果Java将Generics实现为可再生,那么如果没有用于查找T的运行时绑定的反射,这将无法工作。

通过扩展,它是由于对象类型的非泛型方面被实现(可以用getClass()访问),编译器不可能发出这样的字节码,它能够实例化任何键入T,具体取决于呼叫站点。

答案 2 :(得分:0)

您没有创建通用模板的新实例。您正在使用通用模板创建对象实例。

new A<T>(t);

创建一个新的A,这不是通用的。您不一定知道编译时T会是什么,但您知道该对象将是A。事实上,它的美妙之处在于你不必预知T将会是什么,这可以让你创建如此强大的代码,这些代码将是可重用的。想象一下,如果你实现了Stack,那么你对实际的内容类型不感兴趣。您有兴趣好好处理toppoppush操作。如果您不必预测元素是IntegerString还是其他类型,您可以优雅地编写适用于许多不同类的通用代码。

如果我必须预测T是什么,那么我宁愿说它是Object并且能够处理任何对象。事实上我相信这样的事情会在后台发生。另外,另一种选择是使用reflection,但这根本就不干净。