首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

Java的Generics跟c++的Template到底有什么不同

2012-12-29 
Java的Generics和c++的Template到底有什么不同?先了解Java的Generics:根据Java的文档,Java引入Generics一

Java的Generics和c++的Template到底有什么不同?
先了解Java的Generics:
根据Java的文档,Java引入Generics一是为了在编译时提供更强的类型检查,二是为了泛型编程。

编译时,Java靠type erasure来实现Generics:

1. 将所有的泛型参数替换为限定(bound这里如何翻译?)的类型,如果没有限定,就替换为Object类。因此然生的字节码和普通的类文件一样;
2.  为了保证类型安全,必要的时候会是使用cast;
3.  为了维护继承的泛型类型之间的多态的正确性,必要的时候会生成bridge methods。

考虑下面的泛型类,这个类代表单链表的节点。(一下例子均出自java doc)

public class Node<T> {    private T data;    private Node<T> next;    public Node(T data, Node<T> next) }        this.data = data;        this.next = next;    }    public T getData() { return data; }    // ...}


因为T没有被限定,所以Java编译器将其替换为Object:

public class Node {    private Object data;    private Node next;    public Node(Object data, Node next) {        this.data = data;        this.next = next;    }    public Object getData() { return data; }    // ...}


而下面这个例子,因为Node使用了一个父类型被限定的类型参数,所以T被替换为该父类型。

public class Node<T extends Comparable<T>> {    private T data;    private Node<T> next;    public Node(T data, Node<T> next) {        this.data = data;        this.next = next;    }    public T getData() { return data; }    // ...}

替换为:

public class Node {    private Comparable data;    private Node next;    public Node(Comparable data, Node next) {        this.data = data;        this.next = next;    }    public Comparable getData() { return data; }    // ...}


这样貌似很不错,但有时候有问题,看这个例子:
public class Node<T> {    public T data;    public Node(T data) { this.data = data; }    public void setData(T data) {        System.out.println("Node.setData");        this.data = data;    }}public class MyNode extends Node<Integer> {    public MyNode(Integer data) { super(data); }    public void setData(Integer data) {        System.out.println("MyNode.setData");        super.setData(data);    }}

对于下面这段code,
MyNode mn = new MyNode(5);Node n = mn;           n.setData("Hello");   Integer x = mn.data;

经过type erasure之后,code变成了下图中的样子(用Jad反编译的结果)



可以看到,多了一个方法,
 public volatile void setData(Object obj)    {        setData((Integer)obj);    }

这个方法会将Object类型cast成Integer类型调用MyNode.setObject(Integer),被称为bridge method,因为父类Node有setData(Object)这个方法,如果子类没有,根本就无法编译通过。因为实际参数是个String对象,所以在做setData((Integer)obj)的时候会报

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at MyNode.setData(MyNode.java:1)
at MyNode.main(MyNode.java:11)

更多的关于Java Generics的文章可以参考附录【2】-【4】。

从type erasure的角度来看,Java的Generics真的只是Wrapper。

那么c++的模版呢?

摘自【2】里面的的说法:
Java 中的泛型与 C++ 模板的比较
Java Generics 程序的语法在表面上与 C++ 中的模板非常类似,但是二者之间有着本质的区别。
首先,Java 语言中的泛型不能接受基本类型作为类型参数――它只能接受引用类型。这意味着可以定义 List<Integer>,但是不可以定义 List<int>。
其次,在 C++ 模板中,编译器使用提供的类型参数来扩充模板,因此,为 List<A> 生成的 C++ 代码不同于为 List<B> 生成的代码,List<A> 和 List<B> 实际上是两个不同的类。而 Java 中的泛型则以不同的方式实现,编译器仅仅对这些类型参数进行擦除和替换。类型 ArrayList<Integer> 和 ArrayList<String> 的对象共享相同的类,并且只存在一个 ArrayList 类。

参考:
1. http://docs.oracle.com/javase/tutorial/java/generics/index.html
2. http://www.ibm.com/developerworks/cn/java/j-lo-gj/index.html
3. http://www.blogjava.net/DLevin/archive/2011/06/23/352917.html
4. http://freish.iteye.com/blog/1158008

热点排行