Java 的設計者是因為討厭C++的複雜,於是Java 非常簡潔,GC 也讓記憶體管理非常方便,C# 是看中了Java 的GC,和虛擬機技術,希望把微軟的幾大語言整合到.NET 上來。 因此C#從語言上來講並不簡單甚至可以算的上複雜。
兩種語言的設計想法也不一樣,Java 是編譯解釋語言,C#是編譯然後編譯執行語言。 Java 沒有委託,C# 有委託。 Java 傾向於以Interface 實作委託的功能,而在C# 中,Abstract Class 比Interface 發揮了更大功能。
Java 遵循camel 命名規則,C#遵循Pascal 命名規則。但如今越來越多的Java 人開始使用C#, 同時也把camel 命名規則帶到了C#,這可能會讓C#程式碼越來越難讀。為什麼當初C#為什麼不遵循camel 呢? 我看不出camel 命名規則有什麼不好的。
一. 類別名稱.this 與內部類別
在java 中,常看到類似類別名稱.this 的用法,this 就是當前物件實例,為什麼前面會出現類別名稱?對此C# 程式設計師會很納悶。
在Java 中,很多地方使用到了內部類,甚至可以在內部類別中存取外部類別中的成員,這個時候,在內部類別中使用this 的時候,就會出現this 到底是誰的問題,到底是表示內部類別的目前物件實例,還是外部類別的目前物件實例問題。
在Java 中,透過在this 的前面加上外部類別的類別名,表示在內部類別中使用外部類別的目前物件實例。
我們來看下面的一個例子。
// 外部類別定義
public class OuterClass {
// 內部類別定義
private class InnerClass
{
// 內部類別中沒有定義id 成員,這裡存取外部類別中的成員
public int getId(){ return OuterClass.this.id; }
public void setId(int id) { OuterClass.this.id = id;}
// 內部類別中定義了name 成員,直接存取內部類別中的成員, 預設this 存取目前類別中的成員
private String name;
public String getName() { return this.name;}
// 可以在this 的前面加上一個內部類別的名稱
public void setName(String name) { InnerClass.this.name = name;}
// 內部類別中也可以存取外部類別中同名的成員,需要加上外部類別的名稱
public String getOuterName() { return OuterClass.this.name;}
public void setOuterName(String name) { OuterClass.this.name = name;}
@Override
public String toString()
{
return "Id: " + this.getId() + ", Inner Name: " + this.getName() + ", Outer Name: " + this.getOuterName();
}
}
// 外部類別中定義的成員id 和name
private int id;
private String name;
private InnerClass innerInstance;
public OuterClass()
{
this.innerInstance = new InnerClass();
this.innerInstance.setId(20);
this.innerInstance.setName("Tom");
this.innerInstance.setOuterName("Alice");
}
public String toString()
{
return this.innerInstance.toString();
}
}
在C#中,類別區分為嵌套類別和非嵌套類,前者是聲明在其他資料類型內部的類別。後者是直接定義在某一個命名空間的類別。 C# 中很少定義巢狀類別。
非內嵌類別只允許使用public和internal的存取控制,而內建類別則允許使用所有的五種存取控制符,private, protected , internal protected,public和internal。內部類別也可以存取外部類別的所有方法,包括instance方法和private方法,但是需要明確的傳遞一個外部類別的實例。
C#中的內部類別能夠使用外部類別定義的類型和靜態方法,但是不能直接使用外部類別的實例方法,因此,不存在上面的問題。
在C#中,外部類別對於內部類別的作用更像是命名空間,只要存取控制允許,就可以使用下面的方法建立內部類別物件實例。
OuterClass.InnerClass obj = new OuterClass.InnerClass();這個實例與外部類別的任何實例沒有任何直接的關係。類似於Java中的靜態內部類別。
二、類別名稱.class 與類型
在java 中也常看到類別名稱.class 的用法,這個用法相當於C# 中的typeof( 類別名稱),用來取得類型的類型物件實例參考。
java中,每個class都有一個對應的Class對象,當寫好一個類,編譯完成後,在產生的.class檔中,就產生一個Class對象,用來表示這個類的型別資訊。取得Class實例的三種方式:
透過呼叫物件實例的getClass() 方法取得該物件的Class實例。
使用Class的靜態方法forName(),用類別的名字取得一個Class實例。 Class.forName(xxx.xx.xx) 回傳的是一個類別, 作用是要求JVM查找並載入指定的類,也就是說JVM會執行該類別的靜態程式碼段。
類別名稱.calss的方式取得Class實例,對基本資料類型的封裝類,也可以採用.TYPE來取得對應的基本資料類型的Class實例。
C# 中取得類型物件實例的方式更加簡單明確一些。
透過呼叫資料實例的GetType() 方法來取得,這個方法繼承自Object,所以C#中任何物件都有GetType()方法,x.GetType(),其中x為變數名稱。
typeof(x)中的x,必須是具體的類別名稱、型別名稱等,不可以是變數名稱。
透過System.Type 的靜態方法System.Type.GetType()。
三、匿名類
在java 中,匿名類別的使用也比較多,例如在Android 中,實作按鈕的監聽,常常會看到類似這樣的程式碼。
@Override
public void onClick(View arg0) {
Intent intent = new Intent( MainActivity.this, ActivityFrameLayout.class);
setTitle("FrameLayout");
startActivity( intent );
}
};
在這裡,OnClickListenter 實際上是一個接口,接口能用來建立物件實例嗎?當然不能。
所以,java 在這裡自動建立一個實作介面的匿名類,我們創建出來的其實就是這個匿名類別的物件實例。
這樣做的好處就是我們沒有必須再定義一個只使用一次的類,然後再透過這個類別建立物件實例,簡化了程式的開發。
例如,我們有下面的一個介面。
instance.onClick();在C# 中,我們根本就不會使用這種形式,透過委託,可以非常簡單地實現相同的功能。
注意,java 中是沒有委託的。
如果我們輸出一下這個實例的類型,你會看到這個匿名類別的實際類型的。
屬性的概念對大家來說應該是很熟悉的,類別成員函數可以自由地存取本類別中的任何屬性成員。不過若要從一個類別中去存取另一個類別中的屬性,那就比較麻煩了,所以很多時候我們使用Getxxx和Setxxx方法,這樣看起來顯得極不自然,例如用Java或C++,程式碼是這樣的:
但是,在C#中,這樣的方法被「屬性化」了。同樣的程式碼,在C#就變成了:
foo.size++;
label.font.bold = true;
可以看出來,C#顯然比較容易閱讀和理解。我們從這個「屬性方法」的子程式碼中,也可以看到類似情況:
Java/C++:
C#:
為了區分這種屬性化的方法和類別的屬性成員,在C#中把屬性成員稱作“域(field)”,而“屬性”則成為這種“屬性化的方法”專用的名詞。順便說一句,其實這樣的屬性化方法在VB和DELPHI中是經常碰到的,在VB中它也就叫屬性。另外,在C#中Get和Set必須成對出現,一種屬性不能只有Get而沒有Set(在Java和C++中就可以只有Get或只有Set),C#中這樣做的好處在於便於維護,假如要對某種屬性進行修改,就會同時注意Get和Set方法,同時修改,不會改了這個忘了那個。
五、物件索引機制(Indexer)
C#中引入了物件索引機制。說得明白點,物件索引其實就是物件數組。這裡和上一節的屬性連結起來講一下,屬性需要隱藏Get和Set方法,而在索引機制中,各個物件的Get或是Set方法是暴露出來的。例如下面的例子就比較清楚地說明了這一點。以上介紹C#和Java不同點
stories [index] = value;
}
}
}
……
}
以上介紹C#和JAVA得不同點,希望對你了解C#和JAVA有幫助。