`
standalone
  • 浏览: 611407 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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
  • 大小: 102.1 KB
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    Java Generics and Collections (Java泛型与集合)

    通过阅读"Java Generics and Collections",开发者不仅可以掌握Java泛型和集合的基本使用,还能深入了解它们的高级特性和最佳实践,从而在实际项目中编写出更高质量的代码。这本书对于Java程序员来说是一份宝贵的...

    Java Generics FAQ

    Java泛型(Generics)是Java SE 5.0引入的一种新特性,它允许程序员在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。下面将根据给定的文件信息,深入解析Java泛型的一些核心知识点...

    [Java泛型和集合].(Java.Generics.and.Collections).文字版

    本资料 "[Java泛型和集合].(Java.Generics.and.Collections).Maurice.Naftalin&amp;Philip.Wadler.文字版" 由知名专家Maurice Naftalin和Philip Wadler编著,提供了关于这些主题的深入理解。 **Java泛型** 是自Java...

    Java Generics and Collections.chm

    《Java Generics and Collections》是Java开发者必备的参考资料,它深入探讨了Java编程中的泛型(Generics)和集合(Collections)这两个核心概念。在Java编程中,泛型和集合框架是提高代码效率、可读性和类型安全性...

    Java Generics Cheatsheet

    Java中的方法重载指的是在同一个类中可以有多个同名方法,只要它们的参数类型或参数个数不同即可。泛型方法也可以重载,但必须保证在调用时能够明确区分不同的重载方法。 泛型擦除 泛型信息只存在于Java代码编译...

    Java Generics Tutorial

    即便你对其他语言(如C++模板)中的类似特性有所了解,你也会发现Java泛型既有相似之处,也有其独特之处。对于初学者而言,没有先入为主的观念将有助于更好地理解和掌握Java泛型。 #### 简单泛型定义 泛型最常用于...

    Generics_in_the_Java_Programming_Language译文

    Java 中的泛型是 Java 5(JDK 1.5)中引入的一项新特性,旨在解决类型安全和代码重用的问题。泛型允许程序员对类型进行抽象,使得代码更加灵活和可维护。 泛型的优点: 1. 类型安全:泛型可以在编译期检查类型的...

    Generic Programming for Scientific Computing in C++, Java, and C#

    而在Java和C#中,则是通过泛型(generics)来实现。 - **优势**: - **类型安全性**:编译器可以在编译时检查类型,从而避免运行时错误。 - **代码复用性**:能够减少重复代码的数量,提高代码的可维护性和扩展性...

    Java-Generics-and-Collections-2:Java Generics and Collections Java泛型和集合

    将利用碎片时间进行整理和校对,完整的时间段适合做其他需要大量思考的事,如果你有兴趣欢迎提交PR。 TODO 数据校对 目录 2.4 获取和放置原则 2.5 数组 2.6 通配符与类型参数 2.7 通配符捕获 2.8 对通配符的限制 第...

    java-generics-collections:Java核心中的泛型和集合

    在有关Java核心的系列文章中,我们将继续学习2个新内容,即Generics和Collection,它们是Java中非常流行的对象。 泛型格式化参数化数据类型,以便我们可以将类,接口或方法用于许多不同的数据类型。 集合只是具有...

    JavaGenericsFAQ

    1. **Java 泛型基础**:这部分解释了Java泛型的基本概念,包括什么是泛型以及它们的目的和优势。 2. **Java 泛型的语言特性**:这是一个庞大的章节,详细介绍了所有与Java泛型相关的语言特性,如泛型类型、泛型方法...

Global site tag (gtag.js) - Google Analytics