浅谈Java和C#泛型及C++模板

        最近偶然接触到了类型擦除(TypeErasure)这个概念。通过查了一些资料才知道Java和C#的泛型是有一些区别的,当然与C++的模板也不一样。因此做了如下整理。

        泛型的本质就是让你的类型能够拥有类型参数。它们也被称为参数化类型(parameterizedtypes)或者参数的多态(parametricpolymorphism)。

        Java的泛型采用的是类型擦除法,类型擦除是指在运行时去除所有泛型的类型信息。(看不懂的看下面的例子)JVM本身并没有“泛型”的概念,Java语言的泛型只是编译器层面的。而在.NET中,“泛型”是CLR层面上的。在运行时,CLR会为不同的泛型类型生成不同的具体类型代码。因此也有人说Java的泛型是伪泛型,C#的泛型实现地更加彻底。

        Java的做法最大优势在于其兼容性,使用了泛型的代码可以运行在泛型出现之前的JVM上。而.NET中的泛型需要CLR的支持,因此.NET 2.0的程序集无法在CLR 1.0上运行。但C#的这种实现方式,较之Java减少了装箱和拆箱的开销,在性能上有很大的优势。

        下面通过一个简单的例子来阐述之间的区别。

        在C#中,classList {...},这里T是类型参数。我们可以这样写List<Person>  foo=new List<Person>();新类型是通过List构建的,实际上就像是你的类型参数替换掉了原本的类型参数。编译后相当生成了一个ListOfPerson类,这个类跟其它类没什么区别。这样做的好处是非常迅速,不需要类型转换,在代码中通过反射可以知道这是一个包含PersonList。类型信息没有丢失。

   Java中,我们可以这样写ArrayList<Person>  foo =new  ArrayList<Person>();表面上看跟C#是一样的,同样地编译器会阻止你放入不是Person的类型到这个list里。不同点是Java不会创建一个独一的ListOfPerson类。擦除掉了Person的类型信息,相当于只是一个ArrayList。一般要用类型转换,如Person p=(Person)foo.get(1)

   C++中,我们可以这样写std::list<Person>*  foo =new std::list<Person>();它跟C#的方式很像(应该说C#的方式跟C++很像)。它同样保存类型信息,而不是像Java那样丢掉。但是C#Java的输出都是面向虚拟机的。C++是产生原始的x86二进制代码。所有的东西都不是对象,也没有装箱跟拆箱。C++编译器对使用模版来做什么没有限制。可以说C++的模版是更强大。

         PS:关于C++的模版这里还有好多细节性的问题没提,因为只想主要比较一下C#Java的泛型机制是不是类型擦除,所以C++的模版问题就此一笔代过了。上面谈到的如果有什么问题欢迎指正。

 

你可能感兴趣的:(问题分析)