Java当然比C#长,而且Java脱胎于C和C++,是典型的C风格,C#也是脱胎于C和C++,但由于C#晚于Java,也借鉴了很多Java的东西(C#之父Anders Hejlsberg)其实也是微软VJ++的主要架构师),另外,由于C#之父也是Delphi之父,因此,C#的体系架构不可避免的带有Delphi的VCL(代码是开放的,是我学习编程受益最多的地方)的影子.因此,单纯从语言上来说,可以这么讲,C#是C系列的集大成者,也是高级语言中的集大成者。
2)语法和风格
都是C风格,书写上都差不多,至于花括号的摆放,那只是一种习惯。基本的语法,除了一些细微的差别外,两者基本相同,下面是一些差异比较:
A)类和接口的继承和实现:C#都采用符号":"来表示,Java采用关键字"extends"和"implements"
B) 访问限定,Java的default等于C#的internal,其它都是一样的。
C) 常量:Java没有const关键字,一般用final达到类似的效果,在这方面C#有readonly,const等关键字,控制上更为灵活一些.
D) 在类的多态方面:由于Java没有C#的virtual和override关键字,在表达上没有C#细致和明确。Java的公共,保护,缺省方法默认都是虚方法,所以Java比较容易实现动态注入(Spring技术),C#的访问安全控制性要灵活很多,但这个也有不好的地方,就是你想动态注入得时候,可能由于不是虚方法而无法注入。
E)静态方法:C#的静态方法是不能继承的,而Java的静态方法是可以继承的(但不能重写,只能覆盖).由于静态方法和属性是属于类本身的,因此我觉得静态方法的可继承其实是没有必要的,而且不利于程序逻辑的管理。
F)基本数据类型:基本的一些关键字都相同,但C#的多一些,具体的对应这里就不说了,这里特别记录一下的就是:Java中的int和Integer是有区别的,涉及到基本类型的装箱和拆箱,但需要特别注意,Integer是当作引用类型的,比如Integer i1=300,i2=300; i1和i2是不相等的,但Integer i1=100,i2=100; 中i1和i2是相等的,区别就是超过255比较就是不等的,而C#中int和Integer是没有区别的(至少在行为上),C#中的装箱和拆箱是与object相关的,虽然性能上有差别,但从基本数据类型的行为上来说是没有差别的。
另外,C#中为基本类型增加了可空类型,这个估计跟java的引用基本类型类似。
G)对象清除:机制都差不多,Java中的finalize和C#的dispose效用相当.
H)异常机制:两者一样。
I) 数组:C#分为两种数组类型,一种是普通数组,一种是锯齿数组,但java中没有区分。
J)泛型:都来自于C++的模板类和模板方法,用法都差不多就,不过具体细节上估计会有差异,这里还没深入了解,不做断言;
K)流程控制:有差别的是switch,Java沿用了C++做法,分支可以重叠,但C#要求每个分支都必须有break.从防止出错上来说,C#比较好,但不可避免的会失去很多技巧性写法和灵活性。
1) I/O:这个东西其实比较没什么意义,不过java的流概念跟C#的流概念其实都差不多,继承体系都差不多,只是Java中是Input,Output,而C#中是Read和Write.其实各自支持类中的方法名大部分都相同.当然,C# 除了流支持外,还兼容原来的一些文件读写.
2)序列化:对象的序列化两者都有支持,做法都差不多,当然,C# 中除了二进制序列化外,还可以序列化成XML格式(Java中有不有还有待更进一步了解).序列化的用途其实也差不多(主要是RMI).
3)反射机制:两者的反射机制差不多,当然,在这个方面C#的要完善一些,还加入了元属性(Attribute)的概念(Java中有不有类似的东西,学到目前还没发现,Java中的注解在C#中应该是///表达的东西).C#的反射内在机制我比较了解,Java的就不是很了解。但这种东西在Delphi中很早就有类似实现,只是没有现在的C#这样完善。当然,delphi还是欠缺些,而Java和C#都足够用。
4)多线程:这个其实是与语言无关的东东,不过在Java和C#中基本的实现方法还是差不多,类名都一样,只是方法名一个是run,一个叫Execute.Java中可以用Runable接口来简化线程的创建,C# 中是用方法和委托(包括Lamda表达式)来完成同样的工作.C#中的线程池(严格讲这属于框架而不是语言),后台任务之类的可以看作是一些二次封装的东西,没有对比的价值.
5)代码注入:C#和Java都是基于中间语言(C#的IL,Java的字节码),因此在实现代码注入上都比较方便,因此Spring中的面向方面的实现方法在C#中也很容易实现(可以参考我前面的博文).
6)重载:双方都支持方法的重载,而且规则基本差不多.为了简化这种重载C#中可以用参数缺省和params关键字来减少方法的个数,比如public void DoF(params object[] pms),调用的时候可以是DoF(p1),也可以是DoF(p1,p2...)等,这个在Java中是使用"..."来定义的:public void DoF(Object...pms).Java不支持参数缺省,参数缺省有其方便性,但不是必需(Delphi中很早就支持)。
7)委托和事件:这是带有函数指针,回调方法等味道的东东,找了一下,在Java中没有类似的概念,如果需要实现类似的东西,需要用到设计模式,比如观察者,代理等。C#,Delphi都有这个东西,这其实还是个非常好用的东西。我觉得Java完全可以借鉴升级一下(我查了一下,Java确实没有类似的东西,当然,也可能是我孤陋寡闻),Java没有这个可能是源于对纯面向对象语言的追求和对指针滥用的某种不安。
补充:经过查阅资料,Java中也有回调函数的实现,但实际上,这不是真正意义上的回调函数,只是一种模拟类似功能的东西.因为其传入的其实不是方法,而是类.从这个角度来看,我前面说的关于Java没有委托和事件的原因,估计是对的.
8)逆变和协变:其实只要是面向对象编程,存在继承就有这两种情况(方法的参数和返回值)。但大家只要把握一个原则:老子能用的地方儿子也能用,反之则不然。
总结:如果你对数据结构,操作系统,算法,面向对象编程等比较了解,其实相互转换还是比较容易的。做为苦B的程序员,完全没有必要为语言的排名而纠结,学习语言要有凌驾于语言层面之上的意识。
1) 基本架构
两者的基本架构也差不多,Java:Java程序->Java字节码->JVM(JIT).DotNet:C#程序->CIL(通用中间语言)->CLR(JIT).开始的时候Java的字节码是解释执行的,但现在使用的是即时编译技术,C#作为后来者,从一开始就采用了这种技术.就软件的执行架构来说是基本相同的;
2)平台无关性:
Java和DotNet的设计的目标都是平台无关的,但由于微软的操作系统是其主要赢利来源,所以.Net的平台无关性还是大打折扣.不过后面的Java也很难讲,毕竟被oracle收购后,有些东西会改变.
3)开发语言统一:
在这方面Java的设计没有包含这一目标,而dotNet从开始就致力于开发语言的统一,但这个不是java与C#的作为语言的区别,而是两个体系的不同.Dotnet的这一优势对于程序员来说还是比较有吸引力,至少减少了学习成本.但从另一个方面来说,Java和C#相互转换的学习成本都不是很高.
4)基本数据类型:Java的预定义基本类型要少很多,C#的多很多,但这个不妨碍正常使用.当然,由于C#是基于.net框架,其类型也是通用数据类型.由于两者都是为跨平台而设计的,因此其数据类型的长度并不是实际占用内存的大小.实际占用内存大小取决于虚拟机(JVM,CLR)和具体的机器类型(CPU字长).比如byte是8位,假设机器是32位的,你硬是将byte实现为8位,效率肯定会低些(每次取32位,然后通过计算分字节来取).
1、多线程
多线程模型基本相同,都有线程和线程池概念,调用方法一基本相同。线程基类都叫Thread.但由于Java不支持函数引用(delegate),因此线程代码只能以实现了Runnable或者继承Thread的对象的run方法来完成,相对C#来说不够简洁。Java中的线程组和C#中线程池概念类似,但区别还是非常大,Java中的线程组是可以自己创建自己管理的,比较灵活,可控性比较强,而C#中的线程池是由DotNet框架维护,与操作系统比较紧密,是为了减少线程创建开销,而实现的一种线程共享机制,因此性能上比较好。当然,用户的可控性就差一些。 另外Java中的线程组最终可以形成一个线程组树,而C#中的线程池则没有这种机制。
在多线程同步方便,Java提供的机制比较简单,而C#提供的控制更丰富一些。
2、类
主要不同如下:
1)默认的访问级别不同,不特别指明访问级别的情况下,Java默认是公共的(public),C#是私有的;
2)Java的继承是是用extends,实现接口是implements,而C#都是冒号(:)
3)C#提供的internel,Java没有对应的控制方式。
4) Java 不能定义静态类;
当然这都是细节上的差异,但对于嵌套类,双方的处理差别还是很大的,C# 对嵌套类的处理比较简单,嵌套类只是一种定义在类中的类类型,除了访问需要使用路径外(类A中嵌套类别B,则类B的访问是A.B),其它与正常类没什么不同。但Java的处理要复杂些,如果类B是类A中的嵌套类,Java认为类B是属于类A的实例对象的(如果在第3方使用B时,不能用A.B theB = new A.B()完成实例化,而必须类似A theA = new A();A.B theB = theA.new B() 来完成实例化。而且对B有如下限制:
1)在如果不指明B是静态类,则在B中不能定义静态方法,但这个静态指示定义的静态类跟C#有很大的差别,这里的静态指示(static)只是告诉编译器类B有静态方法。虽然类B有static修饰,类B还是可以实例化的,还是是动态类。
2)对于顶层类来说,可以定义静态方法,而嵌套类如果需要定义类方法,则必须使用static修饰符号来修饰类声明。
因此严格来说Java没有C# 那样严格意义上的静态类,Java的静态方法应该叫类方法比较好。
总体来说,Java和C#的机制和语法其实都很相似,但细节上还是有很多的差异。具体的差异可以在实践中再去学习,对于比较生僻的地方的差异也没比要都弄清楚,毕竟学习语言是用来编程解决问题的,而不是用来咬文嚼字的。
测试:
- public class NestedClass {
- protected static String getName1()
- {
- return "xxxx";
- }
- public static String getName2()
- {
- return "dddd";
- }
- private static String getName3()
- {
- return "private";
- }
- protected String getName4()
- {
- return "xxxx";
- }
- public String getName5()
- {
- return "dddd";
- }
- private String getName6()
- {
- return "private";
- }
- public String getName8()
- {
- return "";
- }
- public static String getName9()
- {
- class class1
- {
- public String getName()
- {
- return "ddd";
- }
- public String getName1()
- {
- return "ddd";
- }
- }
- return "";
- }
- public String getName7()
- {
- class class2
- {
- public String getName()
- {
- return "ddd";
- }
- public String getName1()
- {
- return "ddd";
- }
- }
- class2 theA = new class2();
- //匿名类
- Runnable theRun = new Runnable(){
- @Override
- public void run() {
- // TODO Auto-generated method stub
- getName1();
- getName2();
- getName3();
- getName4();
- getName5();
- getName6();
- }
- };
- return "ddd";
- }
- protected class InnerClass1
- {
- public void doSomething1()
- {
- getName1();
- getName2();
- getName3();
- getName4();
- getName5();
- getName6();
- }
- protected void doSomething2()
- {
- this.doSomething3();
- }
- private void doSomething3()
- {
- getName1();
- getName2();
- getName3();
- getName4();
- getName5();
- getName6();
- }
- }
- private class InnerClass2
- {
- public void doSomething()
- {
- getName1();
- getName2();
- getName3();
- getName4();
- getName5();
- getName6();
- }
- }
- public class InnerClass3
- {
- public void doSomething()
- {
- getName1();
- getName2();
- getName3();
- getName4();
- getName5();
- getName6();
- }
- }
- protected static class InnerClass4
- {
- /**
- * 动态方法*/
- public void doSomething1()
- {
- getName1();
- getName2();
- getName3();
- //静态类中不能访问外部类的非静态成员
- //getName4();
- //getName5();
- //getName6();
- }
- protected void doSomething2()
- {
- this.doSomething3();
- }
- //静态方法
- public static void doSomething3()
- {
- getName1();
- getName2();
- getName3();
- //静态类中不能访问外部类的非静态成员
- //getName4();
- //getName5();
- //getName6();
- }
- }
- }
- public class MyTest {
- public static void main(String[] args)
- {
- NestedClass theClass = new NestedClass();
- //嵌套普通类实例化方式
- NestedClass.InnerClass1 theInner = theClass.new InnerClass1();
- //下面这种实例方法是错的.
- //NestedClass.InnerClass4 theInner = new NestedClass.InnerClass4();
- //保护方法
- theInner.doSomething1();
- //公用方法
- theInner.doSomething2();
- //静态的嵌套类实例方法
- NestedClass.InnerClass4 theInner4 = new NestedClass.InnerClass4();
- //静态的嵌套类不能使用如下实例方法
- //NestedClass.InnerClass1 theInner4 = theClass.new InnerClass4();
- NestedClass.InnerClass4.doSomething3();
- theInner4.doSomething1();
- NestedClass.InnerClass4 theInner5 =new NestedClass.InnerClass4();
- theInner5.doSomething1();//public
- //从外面可以访问保护级方法.
- theInner5.doSomething2();//protected
- theClass.getName4();//保护方法可以访问.
- }
- }