這四個概念是 C# 多態機制的基石,混淆它們會導致設計缺陷與面試失利。本文通過**語法對比表**、**代碼驗證**、**經典面試題 (new vs override)** 三維度,建立清晰的認知邊界。
| 維度 | 介面 interface | 抽象類 abstract class |
|---|---|---|
| 實例化 | 不可 | 不可 |
| 字段/狀態 | 不可 (C# 8+ 僅 static) | 可 (instance/static/readonly/const) |
| 方法實現 | 不可 (C# 8+ default 除外) | 可 (虛/非虛/抽象/靜態) |
| 構造函數 | 不可 | 可 (protected 供派生調用) |
| 訪問修飾符 | 默認 public (C# 8+ 可 private/protected/internal) | 完整支援 |
| 繼承關係 | 多實現 (: IFoo, IBar) | 單繼承 (: Base) |
| 語義 | 契約/能力 | 骨架/身份 |
| 特性 | 抽象方法 abstract | 虛方法 virtual |
|---|---|---|
| 所屬類型 | 僅抽象類 | 抽象類/具體類 |
| 方法體 | 不可有 (分號結尾) | 可有 (默認實現) |
| 派生類義務 | 必須 override (除非派生類也是 abstract) | 可選 override |
| 關鍵字 | abstract | virtual |
| 本質 | 強制契約 | 可選擴展點 |
抽象方法 = 無方法體的虛方法 + 強制覆寫語義。
// 手機抽象類:共享狀態 + 抽象核心行為 + 虛擬可選行為
public abstract class MobilePhone {
private string _logo;
public string Logo { get => _logo; set => _logo = value; }
public abstract void Call(); // 必須實現
public virtual void CallAgain() { // 可選覆寫
Console.WriteLine("我再打一個電話");
}
}
// 介面:純能力契約
public interface IClock { void Alarm(); }
public interface IMusicPlayer { void PlayMusic(); }
// 具體實現:單繼承 + 多實現
public class Nokia : MobilePhone, IClock, IMusicPlayer {
public override void Call() => Console.WriteLine("NOKIA打電話沒問題");
public void Alarm() => Console.WriteLine("NOKIA有鬧鐘");
public void PlayMusic() => Console.WriteLine("NOKIA能聽歌");
public override void CallAgain() => Console.WriteLine("算了,不打了"); // 覆寫虛方法
}
// 實例化可無 new (結構體特性,類需 new)
// MobilePhone mp = new Nokia(); // 多態調用
new vs override 隱藏與覆寫
public class A5 {
public virtual void MethodA() => Console.WriteLine("A5.MethodA");
public virtual void MethodB() => MethodA(); // 調用虛方法
}
public class B5 : A5 {
public new void MethodA() => Console.WriteLine("B5.MethodA"); // 隱藏!非覆寫
}
// 測試
var b5 = new B5();
b5.MethodB(); // 輸出什麼?
輸出:A5.MethodA
B5.MethodA 用 new **隱藏** 了基類方法,**未覆寫**虛方法槽位。A5.MethodB 內部調用 MethodA() 走**虛方法分發**,查找槽位發現仍是 A5.MethodA。new 僅影響**靜態綁定** (編譯期類型為 B5 時直接調用),不影響**動態分發**。override = **替換虛方法槽位** (動態分發生效)。new = **新增同名槽位,遮蔽基類** (僅靜態綁定生效)。new,除非極其清楚後果 (如斷開多態鏈)。new 的條件 (結構體專屬)MyStruct s; s.Field = 1;。new (分配堆內存、調用構造函數)。介面定義「能做什麼」,抽象類定義「是什麼」;抽象方法強制「必須做」,虛方法建議「可以做」;
override延續多態,new切斷多態。刻入肌肉記憶,代碼零 Bug,面試零失手。