C#和Java作為獨立發展的兩種程序設計語言,其實有很多相似的地方;當然,其中還是有一些不同的點的;假如一個熟悉C#但不清楚java的程序員去寫java程序,其實沒有多大困難,只是如果清楚了C#和Java中的一些不同的點,應該可以更快的從C#過渡到Java的。
本文主要是列舉了筆者在學習Java過程中和C#比較的一些異同。希望可以給同樣從C#轉向Java的開發人員提供一些信息。
IBM的開發者網站提供了一個不錯的java入門系列,對於初學者來說不妨一看。
https://www.ibm.com/developerworks/cn/java/intro-to-java-course/index.html
另外wiki中其實也已經有一些詳實的對於java和C#的比較,可以參看
https://en.wikipedia.org/wiki/Comparison_of_C_Sharp_and_Java
Namespace(C#) vs Package(java)
C#和java都是面向對象的編程語言;在源代碼的層面,C#的組織結構是命名空間=>類=>方法/變量/常量,而Java稍有不同,用package代替了C#中的namespace,但是所起的作用是類似的。
同樣的,當一個namespace或者package中需要用到其他的命名空間下的類時, C#通過using指定上下文可以訪問的namespace,而Java通過import導入package來達到同樣的目的。
代碼示例
Java
package hello.world; import java.lang.*; public class HelloWorld { private static final int CONSTINT = 100; private String variable; public void method(){} public static void main(String[] args) { System.out.println("Hello World!"); } }
C#
using System; namespace Hello.World { public class HelloWorld { private const int CONSTINT = 100; private string variable; public void Mehtod() { } static void Main(string[] args) { System.Console.WriteLine("Hello World!"); } } }
訪問限定修飾符
C#和Java中,對類型、方法、變量等都可以指定訪問限制修飾,來達到封裝、繼承等等目的。
Java中的訪問限定修飾符的各個訪問限定如下,這個包就是package
| public | 可由任何類調用 |
| protected | 僅能由同一個包中的類或任何子類調用 |
| 無修飾符 | 由同一個包內的任何類調用 |
| private | 僅能由定義它的類調用 |
C#中的訪問限定描述如下,這個里面有一個程序集assembly的概念,和namespace不太一樣。
| public | 可由任何類調用 |
| protected | 僅可以被所定義的類型或者其嵌套類型或者其派生類型調用 |
| internal | 僅可以被程序集中的類訪問 |
| protected internal | 僅可以被所定義類型、派生類型以及任何定義在同一程序集中的類訪問 |
| private | 僅能由定義它的類調用 |
| 無修飾符 | 同internal修飾符 |
屬性
C#有Property的概念,通過簡單的get/set就可以定義public屬性;C#中的屬性本質上就是兩個方法,一個setter,一個getter, 只是C#在語言層面提供了友好的支持。
Java就沒有這種語言層面的支持,如果想實現同樣的功能,必須首先定義變量,然后定義一個Set方法,一個get方法;當然現在很多IDE插件可以幫助做第二步自動生成這兩個方法。
示例如下
C#
namespace Hello.World { public class Person { public int Age { get; set; } } }
Java
package hello.world; public class Person { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Foreach
帶有迭代器的類型,都可以使用foreach語法來比較優雅的替換for循環。Java和C#的語法略有不同。
代碼示例如下
C#
namespace Hello.World { public class HelloWorld { static void Main(string[] args) { foreach (var str in args) { System.Console.WriteLine("Hello World!" + str); } } } }
Java
package hello.world; public class HelloWorld { public static void main(String[] args) { for(String str : args){ System.out.println("Hello World!" + str); } } }
這里順便提一下的是,Java中沒有類似C#中萬能類型var這種定義方式了,所有變量必須要顯示的寫清楚定義類型,這個可能會給寫慣了C#的同學帶來點不適應。
集合
相比於C#, Java內置的集合功能稍顯薄弱,在使用便捷上不如C#。
Java中只有基本的數組類型支持原語類型(int/long/boolean/char etc), 而其他的集合比如List,Map等只能包含對象類型。而在C#中,所有集合都可以同時支持值類型和引用類型。
C#中,對集合中的元素操作可以使用lamda表達式以及linq的方式,對集合中的每個元素進行操作,選擇,過濾,轉換等等,非常方便。而在Java中,直到java 1.8之后,才支持在集合類型后面,借助類似lamda表達式的方式訪問操作集合中的每個元素,並且內置的功能方法非常少。
一些代碼示例如下,可以看到,使用C#代碼精簡不少,並且有不少內置方法可用(如下代碼不考慮性能開銷,只是純粹展示一下C#中對集合操作的各種可能性)。
C#
using System.Collections.Generic; using System.Linq; namespace Hello.World { public class HelloWorld { static void Main(string[] args) { var persons = new List<Person>(); persons.Add(new Person() { Age = 21 }); persons.Add(new Person() { Age = 19 }); persons.Where(p => p.Age > 20).Select(p => p.Age).ToList().ForEach(p => System.Console.WriteLine("Age-{0}", p)); } } }
Java
package hello.world; import java.util.ArrayList; import java.util.List; public class HelloWorld { public static void main(String[] args) { List<Person> persons = new ArrayList<Person>(); Person p1 = new Person(); p1.setAge(21); persons.add(p1); Person p2 = new Person(); p2.setAge(19); persons.add(p2); persons.forEach(p -> { if (p.getAge() > 20) { System.out.println(String.format("Age-%s", p.getAge())); } }); } }
繼承和多態
C#和Java都很好的支持面向對象編程,只是在具體編碼上稍微有些不一樣。
主要在兩點,子類構造的時候對父類的構造;重寫。
構造的傳值這塊,C#把調用父類的構造方法移出到函數外面調用,以示區別,個人覺得這個比較人性化。
重寫這里,Java父類中的任何方法都可以被重寫,只要加上@Override的注解;而C#中需要在父類可能被重寫的方法加上virtual關鍵字,后續子類重寫時,在使用關鍵字override;感覺C#更加嚴謹一些。
另外,C#和Java中限定一個類不能被繼承的關鍵字也不一樣,C#使用sealed,Java是final。
代碼示例如下
C#
namespace Hello.World { public class Person { public virtual void doAction() { System.Console.WriteLine("Person"); } } public class Employee : Person { public Employee() : base() { } public override void doAction() { System.Console.WriteLine("Employee"); } } } namespace Hello.World { public class HelloWorld { static void Main(string[] args) { Person p = new Employee(); p.doAction(); } } }
Java
package hello.world; public class Person { public void doAction(){ System.out.println("Person"); } } public class Employee extends Person{ public Employee(){ super(); } @Override public void doAction(){ System.out.println("Employee"); } } public class HelloWorld { public static void main(String[] args) { Person p = new Employee(); p.doAction(); } }
