2008-12-10 79 views
103

我听说泛型的Java实现不如C#实现。因为语法看起来很相似,那么对于Java实现来说这是不合标准的呢,还是它是一种宗教观点?C#vs Java泛型

+0

看起来像这个问题已经被问 - http://stackoverflow.com/questions/31693/differences-in-generics#31866 – serg10 2008-12-10 13:51:20

+0

综合比较[这里](http://www.jprl.com/Blog/ archive/development/2007/Aug-31.html)和一些链接。 – Strelok 2008-12-10 04:15:34

回答

136

streloksi's link做出了很好的分解差异。虽然是快速和肮脏的总结...

就语法和用法而言。语言之间的语法大致相同。在这里和那里有一些怪癖(最明显的是限制)。但基本上,如果你可以阅读一个,你可能会阅读/使用另一个。

虽然最大的区别在于实现。

Java使用类型擦除的概念来实现泛型。总之,底层的编译类实际上并不是通用的。他们编译成Object和强制转换。实际上,Java泛型是一个编译时工件,可以在运行时轻松地被破坏。在另一方面

C#,凭借CLR的,实现仿制药的所有他们一路下滑到字节码。为了支持2.0中的泛型,CLR进行了几次重大更改。好处是性能改进,深入的类型安全验证和反思。

再次提供link在深度击穿多我建议你阅读

30

区别归结于Microsoft和Sun的设计决定。

Generics in Java通过type erasure由编译器实现,这意味着类型检查发生在编译时,并且类型信息被删除。这种做法被带到保持遗留代码与新的使用代码泛型兼容:

从Java教程,Generics: Type Erasure

当一个泛型类型实例化, 编译器通过 的技术转换的类型称为类型擦除 - 一种 过程,其中编译器移除与类型参数 有关的所有 信息以及类别中的类型参数或 方法。类型擦除使Java 使用泛型的应用程序能够与 保持二进制兼容性 Java库和应用程序 在泛型之前创建。

但是,generics in C# (.NET)没有编译器的类型擦除,类型检查在运行时执行。这样做的好处是类型信息保存在编译后的代码中。

维基百科:

这种设计可以被利用来 提供额外的功能,如 如允许反射与 保存泛型类型,以及 为减轻一些限制擦除 (如因为无法通过 创建通用数组)。这个 也意味着没有 运行时强制转换的性能命中和 通常是昂贵的拳击转换。

与其说“.NET泛型比Java泛型更好”,我们应该研究实现泛型的方法的区别。在Java中,似乎保留兼容性是一个高优先级,而在.NET中(2.0版引入时),实现使用泛型的全部好处是更高的优先级。

+0

@Tom“分析的免疫力”是什么意思? – LamonteCristo 2014-08-15 14:15:45

4

还发现this谈话安德斯·海尔斯伯格可能也很感兴趣。为了总结了安德斯·海尔斯伯格有一些额外的注意事项提出的论点:Java泛型是与现有的JVM,导致一些奇怪的事情与实施方面的最大兼容性您在C#中看到:

  • 类型擦除部队执行代表每个通用参数值为Object。虽然编译器提供Object和更具体的类型之间的自动强制转换,它不会删除类型转换对性能的负面影响和拳击(如Object被转换为特定类型MyClassint曾在Integer进行装箱,这将是如果由于用户定义的值类型而遵循类型擦除方法,那么对于C#/ .NET更为严重)。正如安德斯说:“你没有得到任何的执行效率”(即物化仿制药在C#中启用)

  • 类型擦除使得可用信息在运行时过程中不能访问编译时间。一些曾经是List<Integer>变成只是一个List没有办法在运行时恢复泛型类型参数。 这使得围绕Java泛型构建反射或动态代码生成场景变得困难。最近SO answer显示了通过匿名类变通的办法。但是,如果没有技巧,像通过反射,从一个集合实例获得元素并将其用于另一个集合实例的动态生成的代码执行期间可以在运行时失败在运行时生成代码:反射不与List<Double>在捕错配与List<Integer>帮助这些情况。

但是+1的答案链接到乔纳森普赖尔的blog post