为什么Java中的泛型使用类而不使用基本类型?
例如,这很好用:
List<Integer> foo = new ArrayList<Integer>();
但不允许这样做:
List<int> bar = new ArrayList<int>();
答案 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参数。关于此限制的原因,这是编译器实现的问题。基本类型具有自己的字节码指令,用于加载和存储到虚拟机堆栈中。因此,将原始泛型编译到这些单独的字节码路径中并不是没有可能,但这会使编译器变得复杂。