基礎語法的差異
1. 靜態類
Java 靜態類裏面可以聲明非靜態的屬性和方法,C# 靜態類只能包含靜態的屬性和靜態的方法等
public class People { static String outerStaticField = "I'm static in OuterClass"; // 靜態內部類 static class StaticNestedClass { String innerField = "嵌套內部靜態類的非靜態字段"; static String staticFile="嵌套內部靜態類的靜態字段"; public void printFields() { // 可以訪問外部類的靜態字段 System.out.println(outerStaticField); // 但不能訪問外部類的非靜態字段,因爲靜態內部類不持有外部類的實例引用 // System.out.println(outerNonStaticField); // 這會導致編譯錯誤 System.out.println(innerField); } } }
2. 自定義字符串的語法糖
C# 中可以使用$"....{變量}." 的語法糖去動態寫字符串值,也可以用string.Format方式
string s = "123"; string a1 = $"{s}666"; string a2 = string.Format("{0}666",s);
Java只能通過 String.format 方式,並且C#是直接用{0}代替字符串,而Java是s%代表字符串變量,
%d
代表整數 等
String s = "123"; String a = String.format("%s666", s);
StringBuilder 用法兩者都是差不多,只是 C# 提供的方法多一些
3. foreach循環
C#的foreach
String[] names = { "James", "Larry", "Tom", "Lacy" }; foreach (string name in names) { Console.WriteLine(name); }
Java中沒有foreach, 代替的是 增強型for循環
String[] names = { "James", "Larry", "Tom", "Lacy" }; for (String name : names) { System.out.println(name); }
4. 獲取時間
Java推薦使用 LocalDate 類
//方式一:LocalDate類(需要 Java 8 及以上) // 獲取當前日期 LocalDate date2 = LocalDate.now().plusDays(1); // 增加一天 System.out.println(date2); // 獲取完整日期時間(包含T) ps: 2024-04-28T16:39:38.342 LocalDateTime fullDate = LocalDateTime.now(); System.out.println(fullDate); // 格式化日期時間(不包含T) ps:2024-04-28 16:39:38 LocalDateTime fullDate2 = LocalDateTime.now(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String formattedDate = fullDate2.format(formatter); System.out.println(formattedDate); // 方式二:Date 類(Java 7 以及之前的版本) // 使用 Date 類(Java 7 以及之前的版本): Date date = new Date(); // 使用 toString() 函數顯示日期時間 System.out.println(date); //方式三:使用 Calendar 類(所有版本中都可以使用,但是寫法相對負責) Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, 1); // 增加一天 System.out.println(calendar.getTime());
5. 數據結構
5.1 集合
C# 中只提供了List<T> 方式的集合,集合順序是有序的,按順序插入,還不能按照索引插入。
Java中提供了List和Set兩種,List又分爲ArrayList 和 LinkedList 。Set 分爲 HashSet 和 TreeSet
ArrayList(最常用的集合): 特點: 動態數組,可變大小。 優點: 高效的隨機訪問和快速尾部插入。 缺點: 中間插入和刪除相對較慢。
LinkedList: 特點: 雙向鏈表,元素之間通過指針連接。 優點: 插入和刪除元素高效,迭代器性能好。 缺點: 隨機訪問相對較慢。 HashSet: 特點: 無序集合,基於HashMap實現。 優點: 高效的查找和插入操作。 缺點: 不保證順序。
TreeSet: 特點:TreeSet 是有序集合,底層基於紅黑樹實現,不允許重複元素。 優點: 提供自動排序功能,適用於需要按順序存儲元素的場景。 缺點: 性能相對較差,不允許插入 null 元素。
List
和 Set
區別:
-
重複元素:
List
允許存儲重複元素,而Set
不允許重複元素。 -
元素的順序:
List
是有序的集合,它按照元素插入的順序進行存儲並且可以根據索引訪問元素;而Set
是無序的集合,它不保證元素的存儲順序,也不能通過索引訪問元素。 -
底層實現方式:
List
通常以數組或鏈表的形式實現,例如ArrayList
和LinkedList
;而Set
通常以哈希表的形式實現,例如HashSet
和TreeSet
。
// 使用 List 存儲重複元素 List<String> list = new ArrayList<>(); list.add("apple"); list.add("banana"); list.add("apple"); System.out.println(list); // 輸出: [apple, banana, apple] // 使用 Set 存儲不重複元素 Set<String> set = new HashSet<>(); set.add("apple"); set.add("banana"); set.add("apple"); // 重複元素不會被加入 System.out.println(set); // 輸出: [apple, banana]
ArrayList
和 LinkedList 區別
-
數據存儲方式:
ArrayList
基於動態數組實現,支持隨機訪問,即可以通過索引直接訪問元素;LinkedList
基於雙向鏈表實現,不支持隨機訪問,只能通過迭代器或者從頭/尾部遍歷來訪問元素。 -
插入和刪除操作:對於
ArrayList
,在列表中間或頭部插入/刪除元素時,由於需要移動元素,性能略低於鏈表;對於LinkedList
,由於只需要調整節點的指針,插入/刪除性能很好
// 使用 ArrayList List<Integer> arrayList = new ArrayList<>(); for (int i = 0; i < 10; i++) { arrayList.add(i); } // 使用 LinkedList List<Integer> linkedList = new LinkedList<>(); for (int i = 0; i < 10; i++) { linkedList.add(i); } // 訪問元素 System.out.println(arrayList.get(5)); // 輸出: 5 System.out.println(linkedList.get(5)); // 此處需要遍歷鏈表,輸出: 5 // 插入和刪除操作 arrayList.add(5, 100); // 在索引爲5的位置插入100 linkedList.add(5, 100); // 在索引爲5的位置插入100 arrayList.remove(5); // 移除索引爲5的元素 linkedList.remove(5); // 移除索引爲5的元素
HashSet
和 TreeSet 區別
-
內部實現:
HashSet
使用哈希表來存儲元素,它允許使用null
作爲元素,是一個無序的集合;TreeSet
基於紅黑樹(一種自平衡的二叉查找樹)實現,它不允許使用null
作爲元素,是一個有序的集合。 -
元素排序:
HashSet
不保證元素的順序,元素存儲的順序可能與插入順序不同;TreeSet
則根據元素的自然順序或者提供的比較器進行排序,並且提供了一些額外的有序集合操作方法。 -
插入和檢索效率:
HashSet
插入、刪除和查找元素的效率通常較高,平均時間複雜度爲 O(1);TreeSet
對於插入、刪除和查找元素的效率較低,平均時間複雜度爲 O(logn),因爲它需要維持紅黑樹的平衡。
// 使用 HashSet Set<String> hashSet = new HashSet<>(); hashSet.add("banana"); hashSet.add("apple"); hashSet.add("orange"); System.out.println(hashSet); // 輸出:[orange, banana, apple] // 使用 TreeSet Set<String> treeSet = new TreeSet<>(); treeSet.add("banana"); treeSet.add("apple"); treeSet.add("orange"); System.out.println(treeSet); // 輸出:[apple, banana, orange]
5.2 鍵值對
C# 中使用 Dictionary<Key, Value>
Java使用 Map<Key,Value> 。其中分爲 HashMap和 TreeMap
HashMap(最常用的): 特點: 基於哈希表實現的鍵值對存儲結構。 優點: 高效的查找、插入和刪除操作。 缺點: 無序,不保證順序。
TreeMap: 特點: 基於紅黑樹實現的有序鍵值對存儲結構。 優點: 有序,支持按照鍵的順序遍歷。 缺點: 插入和刪除相對較慢。
基本使用
// 創建一個新的 HashMap Map<String, Integer> map = new HashMap<>(); // 添加元素 map.put("apple", 10); map.put("banana", 20); map.put("orange", 15); // 讀取元素 System.out.println("獲取鍵爲 banana 的值:" + map.get("banana")); // 輸出:20 // 修改元素 map.put("apple", 25); // 輸出Map內容 System.out.println("修改後的Map內容:"); System.out.println(map); // 輸出:{orange=15, apple=25, banana=20} // 移除元素 map.remove("orange"); // 輸出Map內容 System.out.println("移除元素後的Map內容:"); System.out.println(map); // 輸出:{apple=25, banana=20} // 遍歷元素 System.out.println("遍歷Map內容:"); for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); }
6. 類型通配符:?
在C# 中沒有這個類型通配符。
Java中相當於Object,只是比Object範圍更廣泛,?包括了Object。類型通配符更加靈活,並提供了更多的編譯時類型安全性和約束,能夠更好地適應泛型編程的需求.使用類型通配符時,編譯器可以進行更嚴格的類型檢查,確保類型的兼容性。而Object類型在編譯時不提供類型檢查,可能導致運行時的類型轉換錯誤。
public class Printer { public void printValue(List<?> list) { for (Object item : list) { System.out.println(item); } } } public static void printValue2( List<? extends Number> list) { for (Object item : list) { System.out.println(item); } }
面向對象語法
1. 繼承
C# 不管是繼承類還是接口直接使用:進行繼承。
調用父級的方法使用base關鍵字。
如果需要重寫需要在被繼承的父類中寫virtual,override,abstract 關鍵字,在重寫的子類中用 override關鍵字
public class Parent { public void eat() { Console.WriteLine("Parent's logic"); } public virtual void food() { Console.WriteLine("Parent's logic"); } } public class Child : Parent { public void test() { base.eat(); } public override void food() { Console.WriteLine("Child's logic"); } } public class GrandChild : Child { // GrandChild 繼承了 Child 類 public override void food() { Console.WriteLine("Child's logic"); } }
在 Java 中,繼承使用關鍵字extends 來繼承父類, 使用 implements 關鍵字繼承多個接口
調用父級的方法使用 super 關鍵字。
子類要重寫父類的方法,只需要在子類中使用 @Override
註解來顯式地標記即可
class Parent { void printMessage() { System.out.println("Parent's logic"); } void eat() { System.out.println("Parent's logic"); } } class Child extends Parent { @Override void printMessage() { System.out.println("Child's logic"); super.eat(); } } class GrandChild extends Child { // GrandChild 繼承了 Child 類 }
2. 泛型
c# 泛型方法約束條件是寫在尖括號內的泛型參數後面的where子句中,具體來說,where子句是在方法的返回類型之後、緊跟在尖括號後的泛型參數列表之後的位置
public static T Maximum<T>(T x, T y, T z) where T : IComparable<T> { // 方法體 }
JAVA泛型方法的約束條件位置不一樣,寫在返回類型之前的尖括號中的。具體來說,約束條件緊跟在方法修飾符(如public static等)後的尖括號中,並用關鍵字"extends"指定泛型參數的邊界
public static <T extends Comparable<T>> T maximum(T x, T y, T z) { // 方法體 }