【问题标题】:C# developers learning Java, what are the biggest differences one may overlook? [closed]C# 开发人员学习 Java,可能会忽略的最大差异是什么? [关闭]
【发布时间】:2011-01-02 03:37:04
【问题描述】:

对于急于学习 Java 的 c# 开发人员,这两种语言之间是否有任何重大的潜在差异需要指出?

也许有些人可能认为事情是一样的,但有一些重要的方面不应该被忽视? (或者你真的可以搞砸了!)

可能在 OOP 结构、GC 工作方式、引用、部署相关等方面。

【问题讨论】:

标签: c# java


【解决方案1】:

我想到了几个问题:

  • Java 没有自定义值类型(结构),因此不必费心寻找它们
  • Java 枚举与 C# 的“命名数字”方法非常不同;他们更OO。如果你小心的话,它们可以发挥很大的作用。
  • byte 用 Ja​​va 签名(很遗憾)
  • 在 C# 中,实例变量初始值设定项基类构造函数之前运行;在 Java 中,它们运行 之后运行(即在“this”类中的构造函数主体之前)
  • 默认情况下,在 C# 中方法是密封的。在 Java 中,它们默认是虚拟的。
  • C# 中的默认访问修饰符始终是“当前上下文中可用的最严格的访问”;在 Java 中,它是“包”访问。 (值得一读 Java 中的特定访问修饰符。)
  • Java 和 C# 中的嵌套类型的工作方式有所不同;特别是它们具有不同的访问限制,除非您将嵌套类型声明为 static,否则它将隐式引用包含类的实例。

【讨论】:

  • +1 这是一个非常适合初学者的列表。
  • @Jon Skeet:+1,在 Java 7 之前你可能会想念 Lambda 和 LINQ?
  • "在 C# 中,实例变量初始化器在基类构造函数之前运行;在 Java 中它们在它之后运行(即在 "this" 类中的构造函数主体之前)" -- Eeer,你能详细说明这个?不知道我真的明白你在说什么:)
  • @cwap:在C#中,执行顺序是“实例变量初始化器、基类构造器、构造器体”。在 Java 中,它是“超类构造器、实例变量初始化器、构造器主体”。 (实例变量初始值设定项是在声明点为实例变量赋值时得到的。)
  • @cwap:是的,这就是我的意思——后者是一个 object 初始化器。
【解决方案2】:

【讨论】:

    【解决方案3】:

    我很惊讶没有人提到属性,这是 C# 中非常基本的东西,但在 Java 中却没有。 C# 3 及更高版本也自动实现了属性。在 Java 中,您必须使用 GetX/SetX 类型的方法。

    另一个明显的区别是 C# 3 中的 LINQ 和 lambda 表达式在 Java 中不存在。

    Java 中还缺少一些其他简单但有用的东西,例如逐字字符串 (@"")、运算符重载、使用 yield 的迭代器和预处理器。

    我个人最喜欢的 C# 之一是命名空间名称不必遵循物理目录结构。我真的很喜欢这种灵活性。

    【讨论】:

      【解决方案4】:

      有很多不同之处,但我想到了这些:

      • Java 中缺少运算符重载。观察你的 instance.Equals(instance2) 与 instance == instance2(尤其是带字符串的)。
      • 习惯于接口不以 I 为前缀。通常您会看到命名空间或类以 Impl 为后缀。
      • 由于 Java 内存模型,双重检查锁定不起作用。
      • 您可以导入静态方法,而无需在它们前面加上类名,这在某些情况下 (DSL) 非常有用。
      • Java 中的 Switch 语句不需要默认值,并且不能使用字符串作为大小写标签 (IIRC)。
      • Java 泛型会激怒您。 Java 泛型在运行时不存在(至少在 1.5 中),它们是一种编译器技巧,如果您想对泛型类型进行反射,则会导致问题。

      【讨论】:

      • 上次我检查过,字符串没有重载 ==,我也没有听说它是为 Java 7 添加的。但是,它们确实会为字符串连接重载 +。
      • 是的,用 == 比较字符串对于新手来说是一个非常常见的陷阱。 .equals 是你必须使用的。
      • 另外,我不明白关于静态方法的评论。不是几乎所有语言都允许使用静态方法或等效方法吗?
      • 我几乎赞成这一点,但我不同意泛型。我喜欢类型擦除。
      • “Java 中的 Switch 语句不需要默认值” - C# 也不需要。
      【解决方案5】:

      .NET 已经具体化了泛型; Java 已经删除了泛型。

      区别在于:如果你有一个ArrayList<String> 对象,在.NET 中,你可以告诉(在运行时)该对象的类型为ArrayList<String>,而在Java 中,在运行时,该对象的类型为@ 987654323@; String 部分丢失。如果你将非String对象放入ArrayList,系统无法强制执行,只有在你尝试提取该项目后才能知道它,并且强制转换失败。

      【讨论】:

      • ...虽然值得补充的是,如果不进行未经检查的强制转换,您不能将非String 对象放入该列表中,somewhere,编译器会正确警告您那时编译器不能再检查泛型边界。只要您的列表始终存储在List<String> 的变量中,尝试将非字符串对象插入其中就不会编译。
      • “非字符串对象进入 ArrayList,系统无法强制执行”:注意系统确实在编译时强制执行。但是,您可以通过强制转换(或不使用泛型)来规避这种情况;然后运行时检查将捕获它,但仅在提取时。
      • @Andrzej, @sleske:我只是在谈论运行时。假设您通过反射获取对象,并调用其add 方法(同样,通过反射)。系统会立即拒绝非String 对象,还是仅在投射get 的结果时拒绝?
      • @sleske:但是 IIRC 你只需要一个隐式转换来规避类型检查。
      • @Judah:我回滚了您的更改(是的,事后一年),因为您不能拥有List 类型的对象。您可以拥有从List 下降的类型的对象,例如ArrayListLinkedList。 (传递它们时使用List 而不是ArrayList 很重要,但这并不能改变你不能说new List() 的事实。)
      【解决方案6】:

      我在 Java 的 C# 中错过的一件事是强制处理检查的异常。在 C# 中,人们不知道方法可能抛出的异常是很普遍的,而您只能听从文档或测试来发现它们。在带有检查异常的 Java 中并非如此。

      【讨论】:

      • FWIW,这是在 C# 的开发中考虑的,将它们排除在外的理由是真实的。考虑artima.com/intv/handcuffs.html。并不是说设计者在哲学上反对检查异常,而是他们正在等待一种更好的技术,该技术可以提供类似的好处而没有所有毛茸茸的缺点。
      • 是的,是的,一个非常有争议的话题……
      • 我喜欢 C# 没有检查异常这一事实,但这是第一篇甚至指出差异的帖子,所以 +1。
      【解决方案7】:

      Java 对基元而不是值类型进行自动装箱,因此尽管 System.Int32[] 是 C# 中的值数组,Integer[] 是对 Integer 对象的引用数组,因此不适合更高性能的计算。

      【讨论】:

      • Pete:这是一个很好的观点,而且我从来不知道或至少从未考虑过(作为一名 C# 开发人员和 Java 新手)。
      【解决方案8】:

      没有委托或事件 - 您必须使用接口。幸运的是,您可以内联创建类和接口实现,所以这没什么大不了的

      【讨论】:

      • “没什么大不了的”。正确的。因为x => x.Foo vs. new Bar() { public void M(SomeType x) { return x.Foo; } }——谁在乎代码要短 10 倍?
      【解决方案9】:

      与 System.DateTime 相比,Java 中的内置日期/日历功能非常糟糕。这里有很多关于此的信息:What's wrong with Java Date & Time API?

      其中一些可能是 C# 开发人员的陷阱:

      • Java Date 类是可变的,这会使返回和传递日期变得危险。
      • 大多数 java.util.Date 构造函数已被弃用。简单地实例化一个日期是相当冗长的。
      • 我从来没有让 java.util.Date 类与 Web 服务进行良好的互操作。在大多数情况下,两边的日期都会被疯狂地转换为其他日期和时间。

      此外,Java 并没有 GAC 和强命名程序集带来的所有相同功能。 Jar Hell 是链接/引用外部库时可能出错的术语。

      就打包/部署而言:

      • 很难以 EAR/WAR 格式打包 Web 应用程序,这些应用程序实际安装并运行在多个不同的应用程序服务器(Glassfish、Websphere 等)中。
      • 将 Java 应用程序部署为 Windows 服务比在 C# 中需要付出更多的努力。我为此获得的大多数建议都涉及非免费的 3rd 方库
      • 应用程序配置并不像在项目中包含 app.config 文件那么简单。有一个 java.util.Properties 类,但它不那么健壮,并且找到合适的位置来删除 .properties 文件可能会令人困惑

      【讨论】:

        【解决方案10】:

        Java 中没有委托。因此,除了代表带来的所有好处之外,事件的工作方式也不同。您需要实现一个接口并附加它,而不是仅仅连接一个方法。

        【讨论】:

          【解决方案11】:

          在我的面试列表中跳出 b/c 的一件事是,Java 中没有用于方法隐藏的“new”关键字类似物,因此没有编译器警告“你应该在这里放 new”。当您打算覆盖时意外隐藏方法会导致错误。

          (例如编辑) 例如,B 派生自 A(使用 C# 语法,Java 的行为与我上次检查的方式相同,但不会发出编译器警告)。是 A 的 foo 被调用,还是 B 的 foo 被调用? (A 被调用,可能让实现 B 的开发人员感到惊讶)。

          class A 
          {
          public void foo() {code}
          }
          
          class B:A
          {
          public void foo() {code}
          }    
          
          void SomeMethod()
          {
          A a = new B(); // variable's type is declared as A, but assigned to an object of B.
          a.foo();
          }
          

          【讨论】:

          • Java中不小心隐藏了一个实例方法怎么办?它们要么是最终的 - 所以没有覆盖或new 有意隐藏的方法 - 或者是非最终的,因此被覆盖而不是隐藏。
          • 添加示例。好久没用Java测试了,不过面试题最初来自我之前公司的Java组。在 C# 中,编译器警告通常意味着人们更改了名称。我承认这是很奇怪的情况,但 OP 似乎要求的是在切换语言时可能很难找到问题的东西。
          • 这里的区别在于,在 Java 中所有方法都是虚拟的(因此在 Java 中,将调用 B.foo(),因为 Java 总是进行动态方法分派),而在 C# 中方法不是默认情况下是虚拟的(并且 A.foo() 将被调用)。许多 Java 的编码风格检查器会告诉你 B 应该使用 @Override 注释。
          【解决方案12】:

          Java 没有 LINQ,而且文档很糟糕。 Java 中的用户界面开发起来很痛苦,您失去了 Microsoft 给我们的所有好东西(WPF、WCF 等),但却难以使用、几乎没有文档记录的“API”。

          【讨论】:

            【解决方案13】:

            到目前为止,我在使用来自 C# 的 Java 时遇到的一个问题是异常和错误是不同的。

            例如,您无法使用 catch(Exception e) 捕获内存不足错误。

            查看以下内容了解更多详情:

            why-is-java-lang-outofmemoryerror-java-heap-space-not-caught

            【讨论】:

            • 故意设计成这样是为了阻止应用程序程序员抓住它
            • 是的,我确定是这样,但是来自 C# 方面,您所需要担心的只是捕获异常,这让我陷入了循环:)
            【解决方案14】:

            自从我使用 Java 以来已经很久了,但我在应用程序开发中立即注意到的是 C# 事件模型、C# 拖放与在 Swing 中使用布局管理器(如果您正在做应用程序开发),以及使用 Java 进行异常处理,确保捕获异常并且不需要 C#。

            【讨论】:

              【解决方案15】:

              回答您在标题中非常直接的问题:

              “C# 开发者学习 Java,可能会忽略的最大差异是什么?”

              答:Java 在 Windows 上的速度要慢得多。

              【讨论】:

              • 我运行 OpenSuSE 64 位和 Windows 7 64 位,Eclipse IDE 在 Windows 中(“似乎”)更快。您的答案是基于个人观察还是基于实际基准?
              【解决方案16】:

              当我切换到 java 时,对我来说最烦人的区别是字符串声明。

              在 C# string 中(大部分时间) 在Java中String

              这很简单,但相信我,当你习惯使用s 而不是S 时,它会让你浪费很多时间!

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-02-08
                • 1970-01-01
                • 2010-09-10
                • 2014-01-17
                相关资源
                最近更新 更多