C#开发人员在学习Java时,可能会忽略的最大差异是什么?[关闭]


87

对于渴望学习Java的C#开发人员,应该指出这两种语言之间是否存在巨大的根本差异?

也许有些人可能会认为事情是相同的,但是有些重要的方面不容忽视?(或者您真的可以搞砸!)

也许就OOP构造,GC的工作方式,参考,与部署相关的方面而言,等等。




我们自己的“ C#的隐藏功能”也可能会被忽略stackoverflow.com/questions/9033/hidden-features-of-c
John K 2010年

Answers:


122

我头上有些毛病:

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

5
+1这是初学者的好清单。
Jim Schubert

3
@Jon Skeet:+1,在Java 7之前,您可能会想念Lambda和LINQ?
Kb。

1
“在C#中,实例变量初始化程序在基类构造函数之前运行;在Java中,实例变量初始化程序在基类构造函数之前运行(即,在“此”类中的构造函数主体之前)” — Eeer,您能否详细说明一下?不知道我是否真的明白您的意思:)
cwap 2010年

7
@cwap:在C#中,执行顺序为“实例变量初始化程序,基类构造函数,构造函数主体”。在Java中,它是“超类构造函数,实例变量初始化程序,构造函数主体”。(实例变量初始化程序是在声明时为实例变量赋值的结果。)
Jon Skeet 2010年

1
@cwap:是的,这就是我的意思-后者是一个对象初始化器。
乔恩·斯基特


17

令我惊讶的是,没有人提到过属性,这在C#中是相当基本的,而在Java中却没有。C#3及更高版本也自动实现了属性。在Java中,必须使用GetX / SetX类型方法。

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

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

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


10

有很多区别,但是这些对我来说很明显:

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

4
最后我检查了一下,字符串没有重载==,而且我也没有听说过它是为Java 7添加的。但是,对于字符串连接,它们确实会重载+。
Michael Madsen 2010年

3
是的,对于新手来说,将字符串与==比较是一个非常常见的陷阱。.equals是您必须使用的。
迈克尔·迈尔斯

另外,我不了解有关静态方法的评论。并不是所有的语言都允许静态方法或等效方法吗?
迈克尔·迈尔斯

我几乎对此表示赞同,但是我对泛型持不同意见。我喜欢类型擦除。
finnw 2010年

2
“ Java中的Switch语句不需要默认值”-C#也不需要。
RenniePet

8

.NET已对泛型进行了改进;Java删除了泛型。

区别是:如果ArrayList<String>在.NET中有一个对象,则可以(在运行时)告诉该对象具有类型ArrayList<String>,而在Java中,在运行时,该对象是类型ArrayList;该String部分丢失。如果您将非String对象放入ArrayList,系统将无法强制执行该操作,并且只有在您尝试将项目提取出来之后,您才会知道它,并且强制转换失败。


1
......虽然它的价值补充说,你不能把非String对象在该列表中未做一个未经检查的演员,某个地方,编译器会正确地警告你,在这一点上,编译器不能检查的一般界限。只要您的列表始终存储在的变量中List<String>,尝试将非String对象插入其中的尝试就不会编译。
Andrzej Doyle,2010年

“将非字符串对象放入ArrayList中,系统无法强制执行此操作”:请注意,系统确实在编译时强制执行了该操作。但是,您可以通过强制转换(或不使用泛型)来规避此问题;那么运行时检查将捕获它,但仅限于提取时。
sleske 2010年

1
@ Andrzej,@ sleske:我只是在谈论运行时。假设您通过反射获得对象,然后调用其add方法(同样,通过反射)。系统会立即拒绝非String对象还是仅在强制转换结果时拒绝get
克里斯·杰斯特·杨

@sleske:但是IIRC您只需要隐式转换就可以避免类型检查。
Niki 2010年

@Judah:我回滚了您的更改(是的,事实发生后一年),因为您不能拥有type的对象List。您可以使用类型从降序的对象List,例如ArrayListLinkedList。(重要的是使用List而不是ArrayList在传递它们时,但这不会改变您不能说的事实new List()。)
Chris Jester-Young

6

我在Java中用C#错过的一件事是强制处理检查的异常。在C#中,人们通常不知道方法可能会引发的异常,而您只能依靠文档或测试来发现它们,这是很常见的。在带有检查异常的Java中不是这样。


1
FWIW,这是C#开发人员考虑的,将它们排除在外的理由是真实的。考虑使用artima.com/intv/handcuffs.html。并不是说设计人员在哲学上反对检查异常,而是在等待一种更好的技术,该技术可以提供类似的好处,而没有所有毛发的缺点。
格雷格D

是的,是一个非常有争议的主题...
sleske,2010年

2
我喜欢C#没有检查异常的事实,但这是第一篇指出差异的文章,所以+1。
尼克

5

Java具有针对原语而非值类型的自动装箱,因此尽管 System.Int32[]C#中的值Integer[]是数组,但是Integer对象的引用数组,因此不适合更高性能的计算。


1
Pete:这是一个很好的观点,这是我不知道或至少从未考虑过的(是C#开发人员和Java的新手)。
Jim Schubert

4

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


3
“没什么大不了的”。对。因为x => x.Foovs.-new Bar() { public void M(SomeType x) { return x.Foo; } }谁在乎代码短10倍?
Kirk Woll

2

与System.DateTime相比,Java中的内置日期/日历功能令人震惊。这里有很多有关此的信息: Java Date&Time API有什么问题?

对于C#开发人员来说,其中一些可能是陷阱:

  • Java Date类是可变的,可以使返回和传递日期变得危险。
  • 不推荐使用大多数java.util.Date构造函数。简单地实例化一个日期是非常冗长的。
  • 我从未获得过与网络服务良好互操作的java.util.Date类。在大多数情况下,两边的日期都被疯狂地转换为其他日期和时间。

另外,Java不具有GAC和强命名程序集所具有的所有相同功能。 地狱惊魂是链接/引用外部库时可能出问题的术语。

就包装/部署而言:

  • 可能很难以EAR / WAR格式打包Web应用程序,而EAR / WAR格式实际上是在多个不同的应用程序服务器(Glassfish,Websphere等)中安装和运行的。
  • 与C#相比,将Java应用程序部署为Windows服务需要花费更多的精力。我为此提出的大多数建议都涉及一个非免费的第三方图书馆
  • 应用程序配置几乎不像在项目中包含app.config文件那样简单。有一个java.util.Properties类,但是它不那么健壮,找到放置.properties文件的正确位置可能会造成混淆

1

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


1

在我的采访清单上,有一个b / c跳出来的问题是,Java中没有用于方法隐藏的“ 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();
}

2
您如何意外地在Java中隐藏实例方法?它们要么是最终的-因此没有替代或new有意隐藏的方法-或非最终的因此被替代而不是隐藏。
皮特·柯坎

添加了示例。我已经有一段时间没有用Java进行过测试了,但是面试问题最初来自我以前的公司的Java小组。在C#中,编译器警告通常意味着人们会更改名称。我承认这是一个很奇怪的情况,但是OP似乎正在要求切换语言时可能很难发现问题的事情。
Jim L 2010年

1
区别在于,在Java中,所有方法都是虚拟的(因此在Java中,将调用B.foo(),因为Java始终执行动态方法分派),而在C#中,默认情况下,方法不是虚拟的(而A.foo ()将被调用)。Java的许多编码样式检查器都会告诉您B应该使用@Override注释。
William Billingsley,2010年

1

Java没有LINQ,并且说明文档很糟糕。Java用户界面很难开发,您会失去Microsoft提供给我们的所有好处(WPF,WCF等),但是却变得难以使用,几乎没有文档记录的“ API”。


0

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

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

有关更多详细信息,请参见以下内容:

为什么Java lang内存不足错误Java堆空间未捕获


它是经过精心设计的,旨在阻止应用程序程序员抓住它
finnw 2010年

是的,我确定是的,但是来自C#方面,您所需要担心的就是捕获异常,这让我
陷入

0

自从我开始使用Java以来​​已经有很长时间了,但是我在应用程序开发中立即注意到的事情是C#事件模型,C#拖放与在Swing中使用布局管理器(如果您是App开发者)以及使用Java确保您捕获了异常,并且不需要C#。


0

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

“学习Java的C#开发人员,最大的区别是什么?”

答:Java在Windows上的运行速度相当慢。


4
我运行64位的OpenSuSE和Windows 7 64位,并且Windows中的Eclipse IDE速度更快(“似乎”)。您的答案是基于个人观察还是基于实际基准?
Jim Schubert

0

当我切换到Java时,对我最大的困扰是字符串声明。

string在Java中的C#中(大多数情况下)String

这是非常简单的,但相信我,它使你失去了这么多时间,当你有习惯sS

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.