C#与Java泛型[重复]

问题

这个问题在这里已有答案:

  • C#和Java中的Generics与C中的模板有什么区别? [已关闭] 13个答案

我听说Generics的Java实现不如C#实现。因为语法看起来很相似,它对于Java实现是不合标准的,还是宗教观点?


#1 热门回答(139 赞)

streloksi's link在分解差异方面做得很好。快速而肮脏的总结虽然是......

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

但最大的不同在于实施。

Java使用类型擦除的概念来实现泛型。简而言之,底层编译类实际上并不是通用的。他们编译成Object和强制转换。实际上,Java泛型是一个编译时工件,很容易在运行时被破坏。

另一方面,C#凭借CLR实现了泛型,直到字节码。为了支持2.0中的泛型,CLR进行了几次重大更改。优势在于性能改进,深层安全验证和反思。

再次提供的link有更深入的细分,我鼓励你阅读


#2 热门回答(31 赞)

差异归结于微软和Sun的设计决策。

Generics in Java由编译器通过type erasure实现,这意味着在编译时进行类型检查,并删除类型信息。采用这种方法是为了使遗留代码与使用泛型的新代码兼容:

来自The Java Tutorials,Generics: Type Erasure

当实例化泛型类型时,编译器通过称为类型擦除的技术转换这些类型 - 这是一种编译器删除与类型参数相关的所有信息并在类或方法中键入参数的过程。类型擦除使得使用泛型的Java应用程序能够维护与泛型之前创建的Java库和应用程序的二进制兼容性。

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

来自维基百科:

利用此设计选项提供附加功能,例如允许反射并保留泛型类型,以及减轻擦除的一些限制(例如无法创建通用数组)。这也意味着运行时强制转换没有性能损失,通常是昂贵的拳击转换。

不应该说".NET泛型优于Java泛型",而应该研究实现泛型的方法的不同之处。在Java中,似乎保留兼容性是一个高优先级,而在.NET(在2.0版本中引入)时,实现使用泛型的全部好处是一个更高的优先级。


#3 热门回答(4 赞)

同时发现this与Anders Hejlsberg的对话也可能很有趣。总结一下Anders Hejlsberg提出的一些补充说明:Java泛型是为了最大程度地兼容现有的JVM,这导致了一些奇怪的事情,而不是你在C#中看到的实现:

  • 键入擦除力实现以将每个通用参数化值表示为对象。虽然编译器提供了Object和更具体类型之间的自动强制转换,但它并没有消除类型转换和装箱对性能的负面影响(例如,对象被转换为特定类型MyClass或int必须在Integer中加入框,这将是更多如果由于用户定义的值类型而遵循类型擦除方法,则对C#/ .NET严重。正如Anders所说:"你没有获得任何执行效率"(在C#中使用了具体的泛型)
  • 类型擦除使编译时可用的信息在运行时无法访问。曾经是List <Integer>的东西变成了一个List,无法在运行时恢复泛型类型参数。这使得围绕Java泛型构建反射或动态代码生成方案变得困难。更新的SO答案通过匿名类显示了一种解决方法。但是没有技巧,在运行时通过反射生成代码,从一个集合实例获取元素并将其放到另一个集合实例,在执行动态生成的代码时可能会失败:反射无法帮助捕获List <Double>中的不匹配在这些情况下,与List <Integer>相对。

但是对于连接Jonathan Pryor的blog post的答案是1。