早期開發的時候一直用c/c++,後來主要用的是java。最近需要用下c#。
熟悉了下c#,發現c#語言在對c/c++基礎上做了很多簡化,同時參考了很多java的文法習慣,本來在文法上c/c++就有很多和java類似的地方,現在c#就類似的地方更多了,不過還是有很多差別。
本文總結下c# 和c++及 java的文法差别,重點比較與java的差別,便于互相學習,加強了解。
一、c#與c++的差別
相比c++,c#做了很多簡化,使的編寫代碼更加容易,重要的變化由如下方面:
1、抛棄了指針的使用。在c#中沒法使用指針了,在對象成員的調用也隻有一種方式,就是通過 . 來引用。
2、完全面向對象。在c#中,不再有全局的函數了。所有的代碼都必須在類中。連基本的基本類型都有方法,如:
classMyapp
{private static void Main(string[] args)
{int a = 10;string value =a.ToString();int b = int.Parse(value);
}
}
3、沒有了頭檔案的概念,類的定義和實作都在類中。
4、引入了命名空間的概念,用于劃分源代碼,類似java的包的概念。
5、類的繼承上廢除了多繼承的概念,一個類智能有一個父類,而在c++中可以有多個父類。
6、引入了類似java中的接口概念。
7、引入了屬性的概念,簡化了對成員變量的操作。
下面我們重點介紹c# 與java的對比。
二、c#與java基本文法的對比
1、程式架構
同java一樣,c#要求所有的代碼都要在類中,不再同c++一樣,既可以定義類,也可以定義全局的方法。
java程式的入口代碼必須是某個類中的如下的方法 :
public static void main(String[] args);
而在c#中,入口方法是
static void Main(string[] args)
注意:c#中Main的第一個字母M是大寫,且Main方法的參數可以不定義。方法的修飾符也可以不加public。
2、包和命名空間
在java中,通過包來組織java源檔案。在c#中,通過命名空間來組織c#源檔案。 它們的含義和作用是類似的。
差別是,java強制要求java源檔案的存放補錄必須與包路徑嚴格一緻。
在java中,通過import引入包,而在c#中通過using引入命名空間。
兩者都可以通過全路徑來引用類(這樣就不需要import和using了)。
3、基本資料類型
兩者大部分基本類型的名稱都一樣,如 int ,char等。枚舉定義的關鍵字都是 enum。數組定義和使用文法也是類似。
典型的差別是:
1)布爾型在java中是 boolean,而在c#中是bool。
2)字元串類型名在java中 是 String ,而在c#中是 string (第一個字母s是小寫)。
最關鍵的是在java中進行字元串内容的比較要用 equlas方法,而在c#中直接可以用 == 比較。
4、語句
兩者的 if 語句,switch語句,for,while, do ...while,break, continue 使用方式都一緻。
有個差別是,在java中,可以用for循環周遊集合。而在c#中需要用單獨的關鍵字 foreach來周遊,但使用方法一樣。
三、c#與java面向對象文法的對比
java和 c# 都是通過 class關鍵字來定義類,也都不需要頭檔案。類的實作代碼用 { }擴起。
1、類的成員
c#中引入了一個屬性的概念。
我們知道在java中,為了提高安全性,我們定義成員變量一搬建議定義private的,這樣為了其它類能通路該變量,再定義相應的get 和 set 方法,代碼如:
classA{private intnum;public void setNum(intnum) {this.num =num;
}public intgetNum() {returnnum;
}
}classB{public voidtest(){
A a= newA();
a.setNum(10);int num =a.getNum();
}
}
而在c#中,為了簡化操作,引入了一個屬性的概念,舉例如下
classA
{public int num { get; set; }
}classB
{public voidtest()
{
A a= newA();
a.num= 10;int re =a.num;
}
}
在類A中,定義了一個屬性 num,在類B中,直接通過屬性名可以通路,簡化了java中的文法。
在A中定義num時,可以隻有get或set标記,表示隻讀或隻寫的。
上面的方式存在一個問題,如果在get或set操作時需要通過一定的計算來傳回值,既可以采用如下的代碼方式。調用方法不變。
classA
{private int_num;public intnum
{get { return_num; }set { _num = value*2; }
}
}
與上面相比,先定義了一個普通的變量_num(這裡是private的,不讓外部直接通路)。
然後定義了一個屬性num,并且有相應的代碼,其中set代碼中的 value是隐式參數,是在給屬性設定值時傳入的參數。
這和java代碼的使用方式類似了,隻是省去了需要定義 setXXX類似的方法。 另外調用時簡化了,直接通過屬性名就可以。
2、通路修飾符
在java中,有 public, protected,private 和 預設四種級别的修飾符,在定義類和成員時不加修飾符,預設是預設的。
在c#中,預設修飾符需要顯示的用internal關鍵字辨別,并且如果定義時不加修飾符,預設不是internal 而是 private的。并且在c#中,可以 protected internal組合使用,其含義是通路僅限于該類或目前程式集(同一命名空間)的派生類。單獨的protected範圍比protected internal大,允許的派生類不限于目前程式集,加上了internal将派生類限制在目前程式集。
3、類的繼承文法
兩者都支援類的繼承,在c++中支援多個父類,在c#中進行了簡化,同java一樣,一個類隻允許有一個父類。
在java中通過extends關鍵字繼承類,在c#中采用的是c++的文法,用 :後跟父類表示。兩者對父類構造函數的處理機制也不一樣。下面舉例說明。
下面代碼是java的例子:
classA{private intnum;public A(intnum){this.num =num;
}
}classB extends A{public B(intnum) {
super(num);//其它代碼,super語句必須放在第一行。
}
}
可以看出,在java中使用extends關鍵字來繼承父類,用 super方法來調用父類的構造函數。
下面是c#的代碼
classA{private intnum;public A(intnum){this.num =num;
}
}classB : A{public B(int num):base(num) {
}
}
可以看出,在c#中是通過 : 辨別符來繼承父類,而且是通過base關鍵字來調用父類構造函數。
4、接口
在java中,引入了接口類型,一個類可以實作一個或多個接口.
在c#中,參考java引入了接口的機制,注意在c++中沒有接口的機制。
但兩者在實作接口的文法上有些差別,在java中通過implements關鍵字來辨別,而在c#中,使用同繼承一樣。
下面是java的文法例子
interfacehello1{}interfacehello2{}classA implements hello1,hello2{private intnum;public A(intnum){this.num =num;
}
}classB extends A implements hello1,hello2{public B(intnum) {
super(num);//其它代碼,super語句必須放在第一行。
}
}
在java中,當一個類同時需要繼承父類和實作接口時,extends語句要放在 implements語句前。
下面是c#的文法例子
interfacehello1 { }interfacehello2 { }classA:hello1,hello2{private intnum;public A(intnum){this.num =num;
}
}classB : A,hello1,hello2{public B(int num):base(num) {
}
}
在 c#中,當一個類同時需要繼承父類和實作接口時,因為都是跟在 : 後面,需要将父類名放在前面,接口名在後面,如上面例子。
5、重載、重寫(多态)
所謂重載,就是一個類可以有多個方法,方法名一樣,但參數資訊不一樣。這個java和 c#都支援。
所謂重寫,是面向對象程式設計中多态特性的展現。就是子類可以定義和父類一樣的方法,具體執行時是執行父類方法還是子類方法,動态根據執行個體綁定。java和c#都有這個特性,差別是使用文法上有些不同。
java的例子:
package com;public classDemo {public static voidmain(String[] args) {
A a= newA();
a.show();//輸出的是 i am A
B b= newB();
b.show();//輸出的是 i am B
A c= newB();
c.show();//輸出的是 i am B. 多态展現,動态決定調用父類或子類方法。因為c實際是指向B的執行個體
}
}classA {public voidshow() {
System.out.println("i am A");
}
}classB extends A {public voidshow() {
System.out.println("i am B");
}
}
可以看出,子類B通過定義相同的方法,重載了父類A的方法。實際執行時,根據變量指向的具體執行個體決定調用是父類或子類的方法。
c#的例子,c#在多态上的文法參考了c++的特點,需要通過virtual和override關鍵字來辨別。
classMyapp
{private static void Main(string[] args)
{
A a= newA();
a.show();//輸出的是 i am A
B b= newB();
b.show();//輸出的是 i am B
A c= newB();
c.show();//輸出的是 i am B. 多态展現,動态決定調用父類或子類方法。因為c實際是指向B的執行個體
}
}classA {virtual public voidshow() {
System.Console.WriteLine("i am A");
}
}classB : A {override public voidshow() {
System.Console.WriteLine("i am B");
}
}
可以看出,在c#中,要想實作繼承的多态性,需要在父類方法中用virtual關鍵字辨別,然後在子類的方法中用override關鍵字進行辨別。
需要說明的是,對于父類定義的virtual或非vritual方法,子類可以不重載,但也可以定義同樣的方法(沒有用override關鍵字),這是允許的,這時子類的該方法将隐藏父類的方法,這個不是動态的特性。
6、抽象類和抽象方法
有時在父類中定義一個序方法,但該方法在基類中不需要有具體的實作,需要在子類中實作。這個特性java和c#都支援。
隻是文法上有細微差别。這裡舉例說明下。
java的例子:
package com;public classDemo {public static voidmain(String[] args) {
B b= newB();
b.show();//輸出的是 i am B
A c= newB();
c.show();//輸出的是 i am B. 多态展現,動态決定調用父類或子類方法。因為c實際是指向B的執行個體
}
}abstract classA {public abstract voidshow();
}classB extends A {public voidshow() {
System.out.println("i am B");
}
}
在java中,是通過abstract關鍵字辨別抽象類和抽象方法的,具體有如下細節:
1)一個類有抽象方法,其所在的類必須定義為抽象類。
2)子類繼承抽象父類,要麼實作父類的抽象方法,要麼繼續把自己定義為抽象類。
3)抽象方法沒有方法體。抽象類不能執行個體化。
下面是c#中的例子
classMyapp
{private static void Main(string[] args)
{
B b= newB();
b.show();//輸出的是 i am B
A c= newB();
c.show();//輸出的是 i am B. 多态展現,動态決定調用父類或子類方法。因為c實際是指向B的執行個體
}
}abstract classA {abstract public voidshow();
}classB : A {override public voidshow() {
System.Console.WriteLine("i am B");
}
}
除了子類方法定義需要加override關鍵字,其它文法要求與java一樣。另外對抽象類和抽象方法的要求也與java中的要求一緻。
四、c#與java其它對比
1、常量和隻讀字段
在java中,可以通過final來定義隻讀變量,可以使成員變量,可以是方法的内的局部變量,也可以是形參。并且定義和初始化可以一起,也可以分開。
如果是定義的的final成員變量,則需要在構造函數中初始化。 如果是方法内的局部變量,可以在定義後指派。
在c#中,可以用 const關鍵字定義常量,要求必須在定義時了解指派。
在c#中,還可以用 readonly來定義類的成員(注意不能定義局部變量),可以在定義時指派,也可以定義時不指派,而在構造函數中指派。
2、異常處理
java和 c#有類似的異常處理機制和文法,都有 try, catch, finally, throw 這幾個使用關鍵字。 差別是:
1)java中的異常分為檢查時異常和運作期異常兩種,而c#中隻有一種(運作期異常)。
2)在java中 ,catch語句必須帶異常類型參數。
而在c#中,可以不帶,表示是預設的,表示對所有異常處理,但如果定義了多個異常,不帶參數的必須放在最後。
3、參數傳遞
在java中,參數傳遞隻有值傳遞一種方式。對于基本資料類型,如 int等,在方法内無法修改方法的值。
而在c#中,保留了c/c++的特性,通過 ref 和 outer 關鍵字,可以讓形參和實參指向同樣的值,這樣在方法内修改形參的值,方法外的實參值也跟着變化。
不過,為了提高程式的可讀性,建議少用這種特性。
4、内部類
在java中,支援内部類,包括匿名内部類。但在c#中,支援内部類,但不支援匿名内部類。
如下面的匿名内部類在java中是允許的,但在c#中是不行的。
package com;public classDemo {public static voidmain(String[] args) {
A a= newA() {public voidshow() {
;
}
};
a.show();
}
}abstract classA {public abstract voidshow();
}
5、分部類
在c#中,編寫代碼時可以将一個類的定義分到多個cs檔案中,後續由編譯器自動合并。這個在java中不支援。
這個特性感覺很不好,強烈建議正常情況下不要使用。