程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#與JAVA之比較

C#與JAVA之比較

編輯:關於C#

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)的概念

內部類

繼承類的時候不會以某種特定的訪問權限來繼承;

沒有全局函數或者常量,一切必須屬於類;

數組或者字符串都自帶長度計算和邊界檢查;

只使用“.”操作符,沒有“-$#@62;”和“::”;

“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", ...);

呵呵,有了這種特性,我們就再不用怕課堂上老師叫我們寫對象數組這種程序了。

. 指代(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 $#@60; 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為“‘全都是類’先生”,真是其中滋味,盡在不言中啊。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved