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