工作上需要用到Java和C#,兩者語法大同小異,這里做一下簡單對比。
語法對比
Java | C# |
||
訪問修飾符 | public | 修飾類、接口、變量、方法。 對所有類可見。 |
修飾類、接口、變量、方法。 對所有類可見。 |
internal | 無。 | 修飾類、接口、變量、方法。 類,接口的缺省訪問修飾符。 同一個程序集的對象可見。 |
|
protected | 子類可見。 | 子類可見。 | |
private | 類內部可見。 | 變量,方法的缺省訪問修飾符 類內部可見。 |
|
default | 類、接口、變量、方法的缺省修飾符。 同一包內可見。 |
無。 | |
基本類型 | 基本類型,無方法可調用。 作為局部變量時,儲存與棧。作為字段時,跟隨於實例。 |
值類型,繼承object,具有ToString()等方法。 作為局部變量時,儲存與棧。作為字段時,跟隨於實例。 |
|
布爾值 | boolean | bool | |
整形 | short,int,long | short,int,long | |
浮點數 | float,double | float,double | |
可空基本類型 | 例如:Integer是引用類型,Integer是int的包裝類。 | 例如: int?其實是Nullable<int>的語法糖,而Nullable<int>依然是值類型。 | |
布爾值 | Boolean | bool? | |
整形 | Short,Integer,Long | short?,int?,long? | |
浮點數 | Float,Double | float?,double? | |
高精度數值類型 | BigDecimal | decimal? | |
源文件組織 | 導入 | 使用包的概念,關鍵字import導入 | 使用命名空間的概念,關鍵字using導入 |
類文件 | 源文件名要和Public類名保持一致, 最多存在一個Public修飾的類, 文件名后綴是.java |
沒有java中的限制, 文件名后綴是.cs |
|
枚舉 | 枚舉 | 關鍵字enum, 引用類型, 和class差不多,可以有字段和方法, 可以添加私有構造函數 |
關鍵字enum, 值類型, 默認繼承int,可以繼承其他值類型 |
常量 | 常量 | 關鍵字final修飾變量,字段,定義時賦值 | 關鍵字const修飾變量,字段,定義時賦值 關鍵字readonly修飾,可以在構造函數中賦值 |
密封 | 密封 | 關鍵字final修飾方法,類,表示不可繼承,不可重寫 | 關鍵字sealed修飾方法,類,表示不可繼承,不可重寫 |
屬性 | 屬性 | 只有字段概念, 一般情況下是要定義字段XX,方法getXX()和setXX()
|
C#引入屬性概念,簡化了操作, 只需要定義XX{get;set;} |
判斷類型 | 判斷類型 | Instanceof | is |
鎖 | 鎖 | Synchronized | Lock |
接口 | 接口 | 關鍵字 implements, 使用注解@Override |
和繼承類一樣,使用符號: 實現類中的方法,不需要使用override關鍵字, 一般命名需要用大寫字母I開頭 |
類 | 抽象類 | abstract 使用注解@Override |
abstract, 重寫方法需要使用override關鍵字 |
分部類 | 無 |
partial 可以將分布在不同文件,而在相同命名空間下,相同名稱並用partial標識的類合並,多用於wpf,winform框架上。 |
|
匿名類 | 如Runnable hello = new Runnable() { public void run() { System.out.println("hello"); } }; 簡化了定義子類的步驟。 |
無。類似的場景基本都是用委托的 |
|
內部類 | 在new的使用上,內部類要和外部類關聯起來 |
在new的使用上,內部類和外部類用法無區別 |
|
匿名方法 | 匿名方法 | 無。 |
使用delegate聲明匿名方法, 如 delegate(int x) { Console.WriteLine("Anonymous Method: {0}", x); }; |
虛擬方法 | 虛擬方法 | 默認都是虛擬方法 |
virtual標識虛擬方法,子類用override重寫 |
靜態 | 靜態類 | 使用關鍵字static | 使用關鍵字static, 可以有靜態構造函數,
|
傳參 | 引用傳遞 | 無 | 在方法參數加上ref,out,使參數按引用傳遞 即方法內改變參數的值,也會影響到方法外的值 |
不定長參數 | 如int... |
如params int[] |
|
流程控制 | 循環 | 關鍵字for有兩種用法 for(初始化; 布爾表達式; 更新) { //代碼語句 } for(聲明語句 : 表達式) { //代碼句子 } |
分別為for和foreach for(初始化; 布爾表達式; 更新) { //代碼語句 } foreach (聲明語句 in 表達式) |
字符 | 字符 | String,引用類型, 需要使用方法equals比較是否相等 |
string,引用類型, 但用法和值類型類似,可以直接用==比較是否相等, 實現原理就是微軟重載了string的==運算符
|
委托 | 委托 | 無。 | 使用關鍵字Delegate聲明,是存有對某個方法的引用的一種引用類型。 使用+使用委托的多播。 |
泛型 | 泛型 | <T>聲明泛型, T只能是引用類型, 可以用extends和super限制T的類型, <?> 表示通配, 實際上是假泛型。 |
<T>聲明泛型, T可以是引用類型也可以是值類型 使用:表示泛型約束,如T:new()表示T必須要有無參構造函數, 真正的泛型。 |
注解與特性 | 注解與特性 | 使用@聲明注解,如 @Service |
C#引入attribute作為特性,如 [Export(typeof(IPayModule))] { ...... } |
索引器 | 索引器 | 無。 | 定義了索引器,就可以使用[]取值。 |
運算符重載 | 運算符重載 | 無。 | 可以對+,-,==等內置的運行符重載,string的==比較符就是運算符重載的結果。 |
集合 | 列表 | List是接口,ArrayList才是實現類 | IList是接口,List是實現類 |
字典 | Map | Dictionary | |
集合處理 | 流式api, 對象.stream().filter(x->x.getCount()>0).collect(Collectors.toList()) |
Linq 對象.Where(x=>x.Count>0).ToList() 使用上方便很多 |
|
lambda | lambda | ()->{}, 入參類型為函數式接口, 實質上lambda表達式會在編譯階段被轉換為匿名內部類 |
()=>{}, 入參類型為委托delegate |
方法引用 |
類::實例方法
類::靜態方法
對象::實例方法
|
類.方法 |
|
擴展方法 | 擴展方法 |
無。要實現類似功能,要編寫Util類。
|
擴展方法是定義在靜態類的靜態方法,入參中的this代表使用的對象,是單繼承的一種補充。 |
命名規范 | 命名規范 |
接口命名和類命名一樣,如Module。 私有字段小寫字母開頭,如test。 方法命名是小寫字母開頭,如getSomeThing() |
接口命名開頭要加大寫字母I,如IModule。 私有字段開頭要加_,如_test。 方法命名都是單詞首字母大寫,如GetSomeThing() |
小結
基本把語法層面上的常見差異都列出來了,總的來說C#語法上還是先進一些,擼代碼變得更加優雅。另外個人能力有限,有些遺漏和錯誤的,歡迎大家補充和指出。