C#、Java之比较

比较

  很多人说C#是微软用来和Java抗衡的武器,因为二者在很大程度上有着惊人的相似,尽管如此,两者不同的地方也很多,所谓“于细微处见差异”。那么两者的相似和区别都在什么地方呢?我们从今天开始,会从各个角度来对比C#和Java的特点,希望能对正在学习、使用C#的朋友有所帮助。

1、C#和.NET平台的概貌

  2000年6月,微软发布C#语言和.NET平台。C#语言是一种强类型的,面向对象的语言,它具有语法简单、表达力强的特点,而.NET平台则是构成微软的“.NET计划”的基石。

  .NET平台的核心包括两方面,一方面就是著名的通用语言运行机(Common Language Runtime),虽然这个名词起得晦涩了点,不过大家可以拿它和Java的虚拟机来作比较,二者完成的任务大致相同;另一方面就是一大堆通用函数库,这些库函数可以被多种语言调用,并且通过编译都产生一种共同的中间语言(Intermediate Language),这种语言也可以拿Java的字节码来类比,虽然完成的方式有些不一样。

2、C#和Java

  下面简单地把C#和Java的相似处列出来,虽然在这里我们重点讨论的是C#和Java的不同点,但是了解一下二者的相同之处也是很有必要的。

  二者都编译成跨平台的、跨语言的代码,并且代码只能在一个受控制的环境中运行

  自动回收垃圾内存,并且消除了指针(在C#中可以使用指针,不过必须注明unsafe关键字)

  都不需要头文件,所有的代码都被“包(package)”限制在某个范围内,并且因为没有头文件,所以消除了类定义的循环依赖

  所有的类都是从对象派生出来,并且必须使用New关键字分配内存

  用对象加锁的方式来支持多线程

  都具有接口(interface)的概念

内部类

  继承类的时候不会以某种特定的访问权限来继承;

  没有全局函数或者常量,一切必须属于类;

  数组或者字符串都自带长度计算和边界检查;

  只使用“.”操作符,没有“->”和“::”;

  “null”、“boolean”和“bool”成为了关键字;

  任何变量均在使用前进行初始化;

  不能使用整数来返回到if条件语句中,必须使用布尔值;

  “Try”模块后可以有“finally” ;

3. 属性(Property)

  属性的概念对大家来说应该是很熟悉的,类成员函数可以自由地访问本类中的任何属性成员。不过若要从一个类中去访问另一个类中的属性,那就比较麻烦了,所以很多时候我们使用Getxxx和Setxxx方法,这样看起来显得极不自然,比如用Java或者C++,代码是这样的:

  foo.setSize (getSize () + 1);
  label.getFont().setBold (true);

  但是,在C#中,这样的方法被“属性化”了。同样的代码,在C#就变成了:

  foo.size++;
  label.font.bold = true;

  可以看出来,C#显然更容易阅读和理解。我们从这个“属性方法”的子程序代码中,也可以看到类似情况:

Java/C++:

public int getSize()
{
  return size;
}

public void setSize (int value)
{
  size = value;
}

C#:
public int Size
{
 get{return size;}
 set{size = value;}
}

  为了区分这种属性化的方法和类的属性成员,在C#中把属性成员称作“域(field)”,而“属性”则成为这种“属性化的方法”专用的名词。顺便说一句,其实这样的属性化方法在VB和DELPHI中是经常碰到的,在VB中它也就叫属性。

  另外,在C#中Get和Set必须成对出现,一种属性不能只有Get而没有Set(在Java和C++中就可以只有Get或者只有Set),C#中这样做的好处在于便于维护,假如要对某种属性进行修改,就会同时注意Get和Set方法,同时修改,不会改了这个忘了那个。

4、对象索引机制(Indexer)

  C#中引入了对象索引机制。说得明白点,对象索引其实就是对象数组。这里和上一节中的属性联系起来讲一下,属性需要隐藏Get和Set方法,而在索引机制中,各个对象的Get或者Set方法是暴露出来的。比如下面的例子就比较清楚地说明了这一点。

public class Skyscraper
{
 Story[] stories;
 public Story this [int index] {
  get {
   return stories [index];
  }
  set {
   if (value != null) {
    stories [index] = value;
   }
  }
 }
...
}

Skyscraper empireState = new Skyscraper (...);
empireState [102] = new Story ("The Top One", ...);

  呵呵,有了这种特性,我们就再不用怕课堂上老师叫我们写对象数组这种程序了。
5. 指代(Delegate)
  指代这个玩意很特别,它有点象指针,但又不完全是,不过大家还是可以把它理解为一种类型安全的、面向对象的指针。(什么是类型安全和面向对象就不用讲了吧?)顺便提一句,有很多书上把Delegate翻译成代理,我觉得这样翻不够确切,翻译成“指代”更恰当些,道理上吻合,并且还符合它的本来意思——微软本来就是用Delegate来“取代指针”,所以叫“指代”,呵呵。

  说起指代,也许至今Sun还会对它愤愤不已,为什么呢?因为在Sun的标准Java中是没有这个东西的,它是微软99年发布的MSVJ++6添加的“新特性”。为此,两家公司吵得不亦乐乎,并且还专门在网上写了大量文章互相攻击,有兴趣的朋友可以去看看(只有英文版)。
http://www.Javasoft.com/docs/white/delegates.html
http://msdn.microsoft.com/visualj/technical/articles/delegates/truth.asp

  话归正传,指代有什么特点呢?一个明显的特点就是它具有了指针的行为,就好象从Java又倒回到了C++。在C#中,指代完成的功能大概和C++里面的指针,以及Java中的接口相当。但是,指代比起C++的“正宗指针”来又要高明一些,因为它可以同时拥有多个方法,相当于C++里面的指针能同时指向多个函数,并且是类型安全的,这一点体现了它的“对象”特性;而比起Java的接口来,指代高明的地方在于它能可以不经过内部类就调用函数,或者用少量代码就能调用多种函数,这一点体现了它的“指针”特性。呵呵,很有“波粒二象性”的味道吧?指代最重要的应用在于对于事件的处理,下一节我们将重点介绍。

6、事件(Event)

  C#对事件是直接支持的(这个特点也是MSVJ所具有的)。当前很多主流程序语言处理事件的方式各不相同,Delphi采用的是函数指针(这在Delphi中的术语是“closure”)、Java用改编类来实现、VC用WindowsAPI的消息系统,而C#则直接使用delegate和event关键字来解决这个问题。下面让我们来看一个例子,例子中会给大家举出声明、调用和处理事件的全过程。

//首先是指代的声明,它定义了唤醒某个函数的事件信号
public delegate void ScoreChangeEventHandler (int newScore, ref bool cancel);

//定义一个产生事件的类
public class Game
{
 // 注意这里使用了event关键字
 public event ScoreChangeEventHandler ScoreChange;
  int score;
  // Score 属性
  public int Score
  {
   get {
    return score;
   }
   set {
    if (score != value)
    {
     bool cancel = false;
     ScoreChange (value, ref cancel);
     if (! cancel)
     score = value;
    }
  }
}

// 处理事件的类
public class Referee
{
 public Referee (Game game)
 {
  // 裁判负责调整比赛中的分数变化
  game.ScoreChange += new ScoreChangeEventHandler (game_ScoreChange);
 }

 // 注意这里的函数是怎样和ScoreChangeEventHandler的信号对上号的
 private void game_ScoreChange (int newScore, ref bool cancel)
 {
  if (newScore < 100)
   System.Console.WriteLine ("Good Score");
  else
  {
   cancel = true;
   System.Console.WriteLine ("No Score can be that high!");
  }
 }
}

// 主函数类,用于测试上述特性
public class GameTest
{
 public static void Main ()
 {
  Game game = new Game ();
  Referee referee = new Referee (game);
  game.Score = 70;
  game.Score = 110;
 }
}

  在主函数中,我们创建了一个game对象和一个裁判对象,然后我们通过改变比赛分数,来观察裁判对此会有什么响应。

  请注意,我们的这个系统中,Game对象是感觉不到裁判对象的存在的,Game对象在这里只负责产生事件,至于有谁会来倾听这个事件,并为之作出反应,Game对象是不作任何表态的。

  我们注意到,在裁判类的Referee函数中,Game.ScoreChange后面使用了+=和-=操作符,这是什么意思呢?回到我们定义ScoreChange的地方,可以发现ScoreChange是用event关键字修饰的,那么这里的意思就很明白了:ScoreChange是一个事件,而事件被触发后需要相应的事件处理机制,+=/-=就是为这个事件增加/移除相对应的事件处理程序,而且,并不是一个事件只能对应一个处理程序,我们还可以用这两个操作符为同一事件增加/移除数个事件处理程序。怎么样?很方便吧!

  在实际应用中,和我们上面讲的(竞赛-裁判)机制很相近的系统就是图形用户界面系统了。Game对象可以看作是图形界面上的小零件,而得分事件就相当于用户输入事件,而裁判就相当于相应的应用程序,用于处理用户输入。

  指代机制的首次亮相是在MSVJ里,它是由Anders Hejlsberg发明的,现在又用到了C#中。指代用在Java语言中的后果,则直接导致了微软和Sun之间对类和指针的关系产生了大量的争论和探讨。有意思的是,Java的发明者James Gosling非常幽默地称呼指代的发明者Anders Hejlsberg为“‘函数指针’先生”,因为Anders Hejlsberg总是想方设法地把指针变相地往各种语言中放;不过有人在看了Java中大量地使用了各种类后,也戏称Java的发明者James Gosling为“‘全都是类’先生”,真是其中滋味,尽在不言中啊。

时间: 2024-12-29 02:37:16

C#、Java之比较的相关文章

诊断 Java 代码:设计轻松的代码维护

设计 本月,Eric Allen 解释了在使代码更易于维护的同时,避免和控制无理由的变化怎么会是保持代码健壮性的关键.他集中讨论了诸如函数样式代码编写之类的概念,以及标记字段.方法和类的方法来处理并防止可变性.Eric 还解释了本任务中单元测试和重构的角色,并提供了协助实现重构的两个工具.在相关论坛中与作者和其他读者分享您对本文的看法.(您也可以单击本文顶部或底部的"讨论",访问该论坛.)有效调试源自良好的编程.设计易于维护的程序是程序员面临的最困难挑战之一,其部分原因在于程序通常并不

win7上java环境变量设置方法

  Java程序依赖JDK,就像C#程序依赖.NetFrameWork一样. 所以在开发之前,必须在win7或者是linux上,安装jdk(JavaDevelopkit)里面包括java一些工具,还有JRE(JavaRuntimeEnvironment)Java运行环境. 系统:windows7 jdk版本:jdk1.7 安装路径:c:/java 安装JDK时,上图显示的公共JRE和后续单独安装的JRE是一样的.所以只装一个就可以了. 按如上步骤操作,显示出环境变量的配置界面. 新建,添加 变量

Java新手入门教程:新手必须掌握的30条Java基本概念

  Java新手必看教程是什么?当然是绿茶小编带来的Java入门需掌握的30个基本概念啦,掌握了这些概念对于学习Java大大有利,正在学习Java编程的同学们快来看看吧. 1.OOP中唯一关系的是对象的接口是什么,就像计算机的销售商她不管电源内部结构 是怎样的,他只关系能否给你提供电就行了,也就是只要知道can or not而不是how and why.所有的程序是由一定的属性和行为对象组成的,不同的对象的访问通过函数调用来完成,对象间所有的交流都是通过方法调用,通过对封装对象数据,很大 限度上

Java有哪些常用语?Java常用语言汇总

  Java有哪些常用语?不介绍Java 常用语,对Java 的总体介绍就是不完整的.尽管促使Java 诞生的源动力是可移植性和安全性,但在Java 语言最终成型的过程中,其他一些因素也起了重要的作用.接下来,绿茶小编就一一来介绍一下. · 简单(Simple) · 安全(Secure) · 可移植(Portable) · 面向对象(Object-oriented) · 健壮(Robust) · 多线程(Multithreaded) · 体系结构中立(Architecture-neutral)

Java环境变量怎么配置?Java环境变量设置教程

  Java环境变量怎么设置?Java语言拥有跨平台的特性,它编译的程序能够运行在多种操作系统平台上,可以实现"一次编写,到处运行"的强大功能.但是Java需要自己手动配置环境变量,这对于Java新手来说是个不小的难题.接下来,小编就教大家Java环境变量设置方法. Java环境变量设置所需工具: JDK 1.7 安装包 Java环境变量设置步骤: 想要成功配置Java的环境变量,那肯定就要安装JDK,才可以开始配置. 1.安装JDK 向导进行相关参数设置.如图: 4.选择安装的路径,

java实现短地址服务

假设下面是你的视频网站链接列表,如果别人想爬取你的数据十分轻松,看规则就知道数据库是序列自增的 http://www.xxxx.com/video/1 http://www.xxxx.com/video/2 http://www.xxxx.com/video/3 那么解决这一问题,我们可以使用短地址,不对外暴露真实链接,使用对称加密是一个很好的方案. Hashids是一个很好的选择,它提供了JS/PHP/JAVA/PYTHON等编程语言的实现,这里我使用的就是它. 下面是我基于blade框架搭建

Description Resource Path Location Type Java compiler level does not match the version of the instal

Description Resource Path Location Type Java compiler level does not match the version of the instal 解决办法 在项目上右键Properties->Project Facets,在打开的Project Facets页面中的Java下拉列表中,选择相应版本. 有可能是java1.6 改成java6之类的

详解Eclipse Galileo中的快速Java编码

问题 无论您的项目或团队的规模有多大,在编辑代码库时,都会遇到如下的两 个问题: 代码模板 尽管代码模板是提高工作效率的一个理想途径,但需要确 保不能用模板来替代真正的重用,即编写方法或函数以便将它们用于许多位置.如果您有 一大段代码,那么最好在使用代码模板前先考虑采用带有变量的各种方法. 缺乏 一致性 - 当团队中的很多人编辑文件时,难免会有编码上的些许差异,但这些差 异会使代码变得难于读懂和维护.这种情况下,很难搜索到代码差异在何处发生.即便代 码是您一个人写的,如果您忘记了前面代码是如何编

[Java] 方法锁、对象锁和类锁的意义和区别

版权声明:请尊重个人劳动成果,转载注明出处,谢谢! 目录(?)[+] 首先的明白Java中锁的机制 synchronized  在修饰代码块的时候需要一个reference对象作为锁的对象.  在修饰方法的时候默认是当前对象作为锁的对象.  在修饰类时候默认是当前类的Class对象作为锁的对象.   线程同步的方法:sychronized.lock.reentrantLock分析 方法锁(synchronized修饰方法时) 通过在方法声明中加入 synchronized关键字来声明 synch

android java 继承父类里的子类问题!!!!!!!

问题描述 android java 继承父类里的子类问题!!!!!!! 请问各位,java可以继承父类的方法和全部属性,那父类里的子类可以继承使用么? android 可以继承父类的Handler.广播么??