C# 與 Java 語言機制與語法的異同
本文是 從 C# 到 Java 系列的文章。此係列文章是為了方便從 C# 轉到 Java 平臺的工程師快速學習新的語言和平臺。整個系列的目錄請點擊此處瀏覽。
這篇文章從基礎的語言機制、語法層面來分析 C# 和 Java 的不同。部分與虛擬機(CLR | JVM)有關的不同會放在相關的另一篇裡,詳見總目錄。
命名規範
Java
中的方法和變量,無論是否為public
,都要以小寫字母開頭,其餘與 C#
大體相當。
那些簡單的同義詞或近義詞
下面的詞彙,在 Java
和 C#
中是 同義
或 近義
的:
- C# 中獲取一個對象的類型使用
typeof
關鍵詞,Java 中使用.class
,如String.class
;C# 也可以使用對象實例的GetType
方法,Java 中對應的是getClass
方法。參考鏈接; - 代表一個對象的類型的類型,C# 為
Type
類型,Java 則為Class
類型。參考鏈接。 - C# 中的
const
(編譯時常量)和readonly
(運行時常量)在Java
中都是final
,同時還代表了一個類不能被繼承(等同於C#
的sealed
)。 - Java 中的
native
關鍵字(聲明使用 native 實現的代碼)類似於 C# 中的extern
(當聲明非託管的外部方法,如動態鏈接庫時使用)。 string
與String
:在 Java 只有後者,在 C# 中前後兩者是同義詞。- Java 中的
synchronized
等同於 C# 語句塊中的lock
,以及 方法體上的特性MethodImplOptions.Synchronized
。 - Java 中的
transient
(短暫)等同於 C# 的NonSerializableAttribute
,代表在序列化中跳過。 - Java 的
...
操作符等同於 C# 的params
。例如:String... args
,則 args 為一個所有參數組成的數組。
值類型與裝箱
Java
的值類型(Value Types)僅限於原生類型,如 int
、boolen
等。Java
不允許自定義值類型,即 Java
不存在 C# 中的 struct
。
值類型
的作用可以從以下幾個方面來考慮:
- 性能:C# 中的
struct
類型有助於減少 GC、減少內存使用、提高性能,但Java
強大的虛擬機JVM
通過優化部分緩解了這個問題。 - 語義:原生類型無法為
null
,且通過傳值方式賦值。
但是,由於 C# 中的值類型通過傳值類型賦值造成了意外錯誤的可能(例如用類似類的方式在杯傳遞後的值類型中修改成員,試圖影響到原有的值),使用值類型要警惕。
值類型在 Java
中不繼承於 Object,但 C# 中卻繼承,這是通過自動裝箱實現的。Java 的值類型可以通過裝箱變為類實例,比如:
int
=>Integer
float
=>Float
byte
=>Byte
Java
具體的數據類型方面的內容,可以參考本系列文章中的另一篇:數據結構(文章末尾有目錄導航)。
泛型
Java
支持泛型,但其支持的方式和 .NET
差別比較大。Java
的泛型使用 類型擦除
實現。所以,你雖然可以設置某個方法或類有一個類型參數 T
,但是你在其實現內部卻無法獲知與該類型的任何信息,解決方法就是使用一個補償的 class
類型(類似於 C# 中的 Type
類型)參數手工傳遞數據類型。
委託,事件
C# 中的委託(delegate
)用於指向固定某個方法原型(一系列參數、某種返回值)的指針(姑且這麼叫吧)。Java
中沒有 delegate
的概念。
Java 中一般通過接口來實現類似委託的效果。
例如,C#
中假如有下面的定義:
// 定義委託
public delegate void onClickListener(View v);
// 定義委託的實現
public void listener(View v) {
// foo
}
// 使用委託
onClickListener = listener;
onClickListener(this);
在 Java 中可以這樣實現。先定義一個接口:
public interface OnClickListener {
void onClick(View v);
}
然後,使用這個接口來存儲一個匿名類
,其中帶有具體的實現,例如:
OnClickListener listener = new OnClickListener() {
@Override
void onClick(View v) {
// 在此書寫代碼
}
};
// 調用接口
listener.onClick(someView);
除了使用匿名類,也可以讓某個命名類繼承此接口:
public class TestClass implements OnClickListener {
void OnClick(View v) {
// 在此書寫代碼
}
void init() {
OnClickListener listener = this;
// 調用接口
listener.onClick(someView);
}
}
C# 支持事件(event
),其內部是通過委託來實現的。Java 中沒有事件的概念。
一般來說,用於事件或委託的情況,Java 會使用接口
來實現。
例如,C# 中的事件:
public event EventHandler SomeEvent; // 事件的發出者
// 事件監聽
someInstance.SomeEvent += (sender, args) => { /* xxx */ };
大約等價於 Java
中的方法:
// 先定義接口
public interface SomeEventListener {
void onEvent(int arg);
}
// 搞一個東西用來存儲接口的具體實現對象
private ArrayList<SomeEventListener> someEventListeners = new ArrayList<>();
// 在要產生事件的類中,添加一對方法用於監聽或取消監聽
public void addSomeEventListener(SomeEventListener listener) {
someEventListeners.add(listener);
}
public void removeSomeEventListener(SomeEventListener listener) {
someEventListeners.remove(listener);
}
// 觸發事件
for (int i = 0; i < someEventListeners,size(); ++i) {
someEventListeners.get(i).onEvent(5);
}
// 事件監聽者,使用 Java8 中才支持的 Lambd 表達式
someInstance.addSomeEventListener(() -> { /* xxx */ });
// 事件監聽者,使用 Java7 以前版本的 匿名類
someInstance.addSomeEventListener(new SomeEventListener() {
@Override
void onEvent(int arg) {
// 代碼邏輯
}
});
也可以參考這篇文章。
本文是 從 C# 到 Java 系列的文章。此係列文章是為了方便從 C# 轉到 Java 平臺的工程師快速學習新的語言和平臺。整個系列的目錄請點擊此處瀏覽。
© 轉載需附帶本文連結,依 CC BY-NC-SA 4.0 釋出。