为什么Java Generics不支持原始类型?

时间:2010-04-27 13:24:18

标签: java generics primitive

为什么Java中的泛型使用类而不使用基本类型?

例如,这很好用:

List<Integer> foo = new ArrayList<Integer>();

但不允许这样做:

List<int> bar = new ArrayList<int>();

6 个答案:

答案 0 :(得分:219)

Java中的泛型是一个完全编译时的构造 - 编译器将所有泛型用法转换为正确类型的强制转换。这是为了保持与以前的JVM运行时的向后兼容性。

此:

List<ClassA> list = new ArrayList<ClassA>();
list.add(new ClassA());
ClassA a = list.get(0);

变成(大致):

List list = new ArrayList();
list.add(new ClassA());
ClassA a = (ClassA)list.get(0);

因此,任何用作泛型的东西都必须可转换为Object(在此示例中get(0)返回Object),而基本类型则不能。因此它们不能用于仿制药。

答案 1 :(得分:33)

在Java中,泛型以他们的方式工作......至少部分......因为在语言设计 1 之后的几年内,它们被添加到语言中。语言设计者通过提供与现有语言和Java类库向后兼容的设计,将约束用于泛型选项。

其他编程语言(例如C ++,C#,Ada)允许将原始类型用作泛型的参数类型。但这样做的另一面是,这些语言的泛型(或模板类型)的实现通常需要为每个类型参数化生成泛型类型的不同副本。


1 - Java 1.0中未包含泛型的原因是由于时间压力。他们认为他们必须快速发布Java语言以填补Web浏览器提供的新市场机会。詹姆斯·戈斯林曾表示,如果他们有时间的话,他会喜欢加入仿制药。如果发生这种情况,Java语言会是什么样的,这是任何人的猜测。

答案 2 :(得分:6)

集合定义为需要一个派生自java.lang.Object的类型。基本类型根本不这样做。

答案 3 :(得分:6)

在java中,通过使用“类型擦除”实现向后兼容性。 所有泛型类型都在运行时转换为Object。 例如,

public class Container<T> {

    private T data;

    public T getData() {
        return data;
    }
}

将在运行时被视为

public class Container {

    private Object data;

    public Object getData() {
        return data;
    }
}

编译器负责提供适当的强制转换以确保类型安全。

Container<Integer> val = new Container<Integer>();
Integer data = val.getData()

将成为

Container val = new Container();
Integer data = (Integer) val.getData()

现在问题是为什么在运行时选择“对象”作为类型?

  

答案是对象是所有对象的超类,可以代表任何对象   用户定义的对象。

     

由于所有原语都不会从“对象”继承,因此我们无法使用它   作为通用类型。

仅供参考:Valhalla项目正试图解决上述问题。

答案 4 :(得分:2)

根据Java Documentation,泛型类型变量只能用引用类型实例化,而不能用基本类型实例化。

这应该是Project Valhalla下的Java 10。

Brian Goetz上的State of the Specialization论文

关于原语不支持泛型的原因有一个excellent explanation。并且,how it will be implemented在未来的Java版本中。

  

Java当前已擦除的实现,它为所有引用实例化生成一个类,并且不支持原始实例化。 (这是一种同类翻译,Java的泛型只能超过引用类型的限制来自于JVM的字节码集的同构转换的局限性,JVM使用不同的字节码对引用类型和原始类型进行操作。)但是,Java中的擦除泛型提供了行为参数(通用方法)和数据参数(泛型类型的原始和通配符实例)。

...

  

选择了一种同构翻译策略,其中泛型类型变量被删除到它们的边界,因为它们被合并到字节码中。这意味着无论一个类是否是泛型,它仍然编译为具有相同名称的单个类,并且其成员签名是相同的。在编译时验证类型安全性,并且通用类型系统不受运行时限制。反过来,这强加了泛型只能在引用类型上工作的限制,因为Object是最常用的类型,并且它不会扩展到原始类型。

答案 5 :(得分:0)

创建对象时,不能用原始类型代替type参数。关于此限制的原因,这是编译器实现的问题。基本类型具有自己的字节码指令,用于加载和存储到虚拟机堆栈中。因此,将原始泛型编译到这些单独的字节码路径中并不是没有可能,但这会使编译器变得复杂。