Intro
泛型编程是抽象类型的抽象能力,它在1970年代首次引入。 它有助于代码维护,减少冗余代码并实现优化。 程序员不必一次又一次地编写相同的算法,而是每次使用不同的数据类型,而只需要编写一次即可。 例如,定义size_t sum(T)而不是三个定义size_t sum(int),size_t sum(long),and size_t sum(双精度)。
C ++允许通过模板进行通用编程,这些模板已包含在1998年标准中,但早在《带注释的C ++参考手册》中就已出现。 Java允许通过泛型进行泛型编程,泛型是2004年Java 5引入的。
Two Different Design Paradigms
它们在表面上可能看起来相似,但是具有相反的设计范例。C ++模板使用代码生成,而Java泛型使用类型擦除。
Type erasure removes the type of an object and adds a cast in the compiled bytecode. It doesn’t actually add anything new to the language. For example, as described in Java Generics and Collections, the bytecode of
List words = new ArrayList();
words.add(“Hello”);
String s = (String) words.get(0);
和
List<String> words = new ArrayList<>();
words.add(“Hello”);
String s = words.get(0)
一样! 很好奇,如果语法如此不同,那么Java委员会为什么会决定它们应该输出相同的字节码? 毕竟,插入类型转换和删除类型似乎会阻止潜在的优化。
替代方法是让泛型引入不同的字节码。 但是,使用泛型并用Java 5编译的代码将不再与之前没有泛型的编译后的代码兼容。 已经使用Java的企业会犹豫要迁移到较新版本。 类型擦除是业务需求和语言增强之间的折衷方案。
类型擦除还可以确保只有一个泛型类型的实现。 例如,清单<String>,清单<Integer>,and 清单<MyClass>都具有相同的实现清单。
与此相比,C ++模板从一开始就包含在标准中并使用代码生成,vector<string>,vector<int>,and vector<MyClass> each has its own implementation. Although this may increase the size of each translation unit and the final executable,implementation-specific types offer the programmer greater flexibility,including:
- 模板功能和类的专业化以实现优化。 一个例子是vector<bool>,这是vector的节省空间的版本创建相同类型的成员变量。 在Java中,类型擦除使得几乎不可能实例化类型的变量,例如T [] t =新的T [10];此外,静态成员变量不能引用泛型类型静态多态性,例如STL容器,并使用typedef进行通用操作,例如使用迭代器很多复杂的东西,例如策略特征和元编程,可以在编译时计算素数!
代码生成与类型擦除的影响会影响语言的性能和可读性。 尽管模板为程序员提供了更大的灵活性,但是由于棘手的规则会导致不便的错误,因此模板更难以使用。 另外,没有什么比阅读跨越数百个字符的隐式错误消息要干的多了。
简而言之,C ++和Java具有不同的模型来启用通用编程。 C ++使用模板和代码生成,而Java使用泛型和类型擦除。