C#和Java之间的主要区别是什么?

209
我只是想澄清一件事。这不是关于哪个更好的问题,那部分我留给其他人讨论。我不在乎它。
我在面试中被问到这个问题,我觉得学习更多可能会有用。
以下是我能想到的:
- Java是“平台无关”的。现在你可以说有Mono项目,所以C#也可以考虑,但我认为有点夸张。为什么?当Java发布新版本时,它同时在所有支持的平台上提供,另一方面,C# 3.0的多少特性在Mono实现中仍然缺失?或者我们应该比较CLR vs. JRE? - Java不支持事件和委托。据我所知。 - 在Java中,所有方法都是虚拟的。 - 开发工具:我相信还没有像Visual Studio这样的工具。特别是如果你使用过团队版本,你就会知道我的意思。
请添加其他您认为相关的内容。
更新: 刚刚想起来,Java没有像类、方法等上的自定义属性。或者它有吗?

1
语言与语言实现不同,而语言实现也不同于库。你想要比较什么? - Miguel Ping
1
请查看C#和Java的比较 - gimel
2
我找到了这个网站 http://msdn.microsoft.com/en-us/library/ms836794.aspx 它涵盖了C#和Java之间的相似性和区别。 - Bipul
1
你可以通过正确的库获取下面提到的许多关于Java的内容。例如,检查此有效的Java代码:new String[] { "james", "john", "john", "eddie" }.where(startsWith("j")).distinct(); 它使用了一个名为lombok-pg的库。可以在github.com/nicholas22/jpropel找到它。 - NT_
7个回答

328

比较Java 7和C# 3

(这里没有提到所有Java 7的特性,但所有版本的C#优于Java 1-6的using语句优势已被移除。)

并不是你的摘要全部正确:

  • 在Java中,方法默认为虚拟的,但可以使它们变为final。 (在C#中,默认情况下它们是sealed的,但可以使它们变为virtual。)
  • 有很多Java的IDE,包括免费的(例如Eclipse,Netbeans)和商业的(例如IntelliJ IDEA)。

除此之外(以及你的摘要中已经包含的内容):

  • Java和C#的泛型完全不同;Java的泛型只是一种编译时的“技巧”(但确实很有用)。 在C#和.NET中,泛型在执行时也保留下来,并且针对值类型和引用类型工作,保持适当的效率(例如,一个List<byte>作为支撑它的byte[],而不是一个装箱字节的数组。)
  • C#没有已检查异常
  • Java不允许创建用户定义的值类型
  • Java没有操作符和转换重载
  • Java没有迭代器块以简单实现迭代器
  • Java没有类似于LINQ的任何东西
  • 部分原因是由于没有委托,Java没有像匿名方法和lambda表达式这样的东西。 匿名内部类通常填充这些角色,但不太优雅。
  • Java没有表达式树
  • C#没有匿名内部类
  • C#实际上根本没有Java的内部类 - 在C#中的所有嵌套类都像Java的静态嵌套类
  • Java没有静态类(它们没有任何实例构造函数,并且不能用于变量、参数等)
  • Java没有与C# 3.0的匿名类型相当的功能
  • Java没有隐式类型的本地变量
  • Java没有扩展方法
  • Java没有对象和集合初始化器表达式
  • 访问修饰符有些不同——在Java中当前没有汇编的直接等效项,因此没有“内部”可见性的概念;在C#中没有与Java中考虑命名空间(和继承)的“默认”可见性等效项。
  • Java和C#的初始化顺序略有不同(C#在调用基类型构造函数之前执行变量初始化器)
  • Java没有将属性作为语言的一部分;它们是get/set/is方法的惯例
  • Java没有“unsafe”代码的等效项
  • C#中的Interop比Java的JNI更容易(以及.NET通用)
  • Java和C#对枚举的理解有所不同。Java的枚举更加面向对象。
  • Java没有预处理器指令(C#中的#define,#if等)。
  • Java没有与C#的ref和out等效项传递参数的引用
  • Java没有partial类型的等效项
  • C#接口无法声明字段
  • Java没有无符号整数类型
  • Java没有语言支持十进制类型。 (java.math.BigDecimal提供了类似于System.Decimal的东西,但没有语言支持)
  • Java没有可空值类型的相应等效项
  • 在Java中,装箱使用预定义(但“正常”)的引用类型及其特定的操作。在C#和.NET中,装箱是一个更透明的过程,CLR会为任何值类型创建一个引用类型用于装箱。
  • 这不是详尽无遗的,但涵盖了我能想到的所有内容。


    24
    我认为Java泛型和内部类的细节很快就否定了Java通过简单性达到卓越的想法。 - Jon Skeet
    8
    @OrangeDog:在我看来,那些争论的人大多数都是自欺欺人。很难说被迫编写显式的try/finally块比使用语句更少出错,在我看来。与Java相比,C#的大多数“额外”功能意味着你可以用更少的代码完成任务,并且该代码更易读。 - Jon Skeet
    17
    你对公正性有多在意?是的,我是一名C#爱好者,但也有相当丰富的Java经验——毕竟这是我的日常工作。并不是说我不知道如何有效使用Java。 - Jon Skeet
    8
    首先,就我所知,大多数开发人员并不使用"unsafe"编写代码,因此这是一个红鱼。我还认为可证明性是一个红鱼 - 我认为形式化可证明性与人类推理代码的难易程度关系不太大。我的观点是,作为一个在Java和C#两个语言中都非常有经验的人,我认为C#在生产力和可读性方面是一种更为优越的语言。如果您持相反意见,请说明您在两种语言中的经验水平。我认为这对讨论非常相关。 - Jon Skeet
    21
    此外,你声称“能够做更多的事情会增加出错的可能性”是我个人认为的谬论...因为它假设如果你不能使用语言特性来完成某些任务,你就根本不需要去完成这些任务。这显然是不正确的 - 在Java和C#中需要完成的任务通常是相同的,但由于缺少一些特性,Java使得完成这些任务变得更加困难。通过简化任务,这些特性反而降低了你出错的可能性。 - Jon Skeet
    显示剩余53条评论

    24

    2
    @Jon Skeet:你是最活跃的C#开发者。为什么不维护一下你自己的C#和Java的区别版本呢?我敢打赌人们会喜欢阅读它的。 - claws
    1
    @claws:我没有时间做我想做的一切。 - Jon Skeet
    19
    我们需要一份“查克·诺里斯和乔恩·斯基特的区别”清单: 1)查克·诺里斯总是有时间;乔恩必须修改“TimeDate”类才能始终拥有时间,但他还没有时间去做。 - D'Arcy Rittich

    11

    C#具有自动属性,它们非常方便,而且可以帮助保持代码的清晰易读性,至少在getter和setter中没有自定义逻辑时如此。


    10

    C#拥有的Java缺少的特性:

    • C#包含更多的基本类型以及捕获算术异常的功能。

    • C#比Java提供更多的符号方便,其中许多符号(例如操作符重载和用户定义的强制转换)已经为C++程序员所熟知。

    • 事件处理在C#中是“一等公民”——它是语言本身的一部分。

    • 允许定义“结构体”,这类似于类但可以在栈上分配(与C#和Java中的实例不同)。

    • C#将属性作为语言语法的一部分实现。

    • C#允许switch语句对字符串进行操作。

    • C#允许提供闭包功能的匿名方法。

    • C#允许使用函数式风格的yield关键字实现协程的迭代器。

    • C#支持输出参数,有助于返回多个值,这是C++和SQL共享的特性。

    • C#具有别名命名空间的能力。

    • C#具有“显式成员实现”功能,允许类专门实现接口的方法,与其自身的类方法分开。这还允许它实现两个具有相同名称方法的不同接口。接口的方法不需要是公共的;它们可以仅通过该接口访问。

    • C#与COM集成。

    • 继承C和C++的示例,C#允许对基元类型和引用类型进行按引用调用。

    Java拥有的C#缺少的特性:

    • Java的strictfp关键字保证浮点数运算结果在不同平台上保持一致。

    • Java支持已检查的异常以更好地执行错误跟踪和处理。


    9
    另一个很好的资源是http://www.javacamp.org/javavscsharp/,该网站列举了许多示例,说明了这两种编程语言之间几乎所有的差异。
    关于属性,Java有注释(Annotations),它们的工作方式几乎相同。

    5

    泛型:

    使用Java泛型时,你实际上没有获得与.NET相同的执行效率,因为在编译Java中的泛型类时,编译器会取走类型参数并在所有地方替换为Object。例如,如果你有一个Foo<T>类,Java编译器生成的字节码就像是Foo<Object>一样。这意味着强制转换和装箱/拆箱都必须在“后台”完成。

    我已经玩了一段时间的Java/C#,在我看来,语言层面上的主要区别就是委托。


    这是错误的,泛型擦除或具体化(分别针对Java和C#)并不一定会影响性能。 - Miguel Ping
    你把自动装箱和强制类型转换混淆了。 - JesperE
    3
    不,Bruno 在性能差异方面是正确的。在 Java 中,没有办法获得等效于 List<byte>(通用)的东西。您需要有一个 List<Byte>,这将产生装箱惩罚(时间和内存)。 - Jon Skeet
    1
    请查看此文章:http://www.jprl.com/Blog/archive/development/2007/Aug-31.html - bruno conde
    总之,使用C#泛型可以提高性能,在Java中则相反 :) - nawfal
    显示剩余2条评论

    0
    请点击下面的链接进行查看: msdn.microsoft.com/en-us/library/ms836794.aspx 它涵盖了C#和java之间的相似性和差异。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接