我听说Generics的Java实现不如C#实现那么好.因为语法看起来很相似,那么Java实现的不合标准是什么,还是宗教观点呢?
streloksi的链接可以很好地打破差异.快速而肮脏的总结虽然是......
在语法和用法方面.语言之间的语法大致相同.这里和那里有一些怪癖(最明显的是在约束中).但基本上如果你能读一个,你可以阅读/使用另一个.
但最大的不同在于实施.
Java使用类型擦除的概念来实现泛型.简而言之,底层编译类实际上并不是通用的.他们编译成Object和强制转换.实际上,Java泛型是一个编译时工件,很容易在运行时被破坏.
另一方面,C#凭借CLR实现了泛型,直到字节码.为了支持2.0中的泛型,CLR进行了几次重大更改.优势在于性能改进,深层安全验证和反思.
再次提供的链接有更深入的细分我鼓励您阅读
差异归结于微软和Sun的设计决策.
Java中的泛型是通过编译器的类型擦除实现的,这意味着类型检查在编译时发生,并且类型信息被删除.采用这种方法是为了使遗留代码与使用泛型的新代码保持兼容:
来自The Java Tutorials,Generics:Type Erasure:
当实例化泛型类型时,编译器通过称为类型擦除的技术来转换这些类型 - 这是一种编译器删除与类型参数相关的所有信息并在类或方法中键入参数的过程.类型擦除使得使用泛型的Java应用程序能够维护与泛型之前创建的Java库和应用程序的二进制兼容性.
但是,对于C#(.NET)中的泛型,编译器没有类型擦除,并且在运行时期间执行类型检查.这样做的好处是类型信息保留在已编译的代码中.
来自维基百科:
利用此设计选项来提供其他功能,例如允许反射并保留泛型类型,以及减轻擦除的一些限制(例如无法创建通用数组).这也意味着运行时强制转换没有性能损失,通常是昂贵的拳击转换.
不应该说".NET泛型优于Java泛型",而应该研究实现泛型的方法的不同之处.在Java中,似乎保留兼容性是一个高优先级,而在.NET(在2.0版本中引入)时,实现使用泛型的全部好处是一个更高的优先级.
还发现这个与Anders Hejlsberg的对话也很有趣.总结一下Anders Hejlsberg提出的一些补充说明:Java泛型是为了最大程度地兼容现有的JVM,这导致了一些奇怪的事情,而不是你在C#中看到的实现:
键入擦除力实现以将每个通用参数化值表示为Object
.虽然编译器提供了Object
更多特定类型之间的自动转换,但它并没有消除类型转换和装箱对性能的负面影响(例如,转换Object
为特定类型MyClass
或int
必须装箱Integer
,这对于C#/更为严重. NET,如果由于用户定义的值类型而遵循类型擦除方法).正如Anders所说:"你没有获得任何执行效率"(在C#中使用了具体的泛型)
类型擦除使编译时可用的信息在运行时无法访问.以前的某些东西List
变得List
无法在运行时恢复泛型类型参数.这使得围绕Java泛型构建反射或动态代码生成方案变得困难.更新的SO答案通过匿名课程展示了一种解决方法.但是没有技巧,比如在运行时通过反射生成代码,从一个集合实例获取元素并将其放到另一个集合实例,在运行时可能会在执行动态生成的代码时失败:反射无助于捕获List
与List
这些情况相比的不匹配.
但是链接+1给Jonathan Pryor的博客帖子.