《Effective Java》第 19-22 條針對 C 語言結構、聯合、枚舉、函數指針在 Java 中的替代方案。Java 無結構體、聯合、枚舉(JDK 5.0 前)、函數指針,但通過類、接口、枚舉類型(5.0+)提供更安全、更具表達力的替代。本文梳理四大替代模式與核心原則。
C 結構體公開所有字段,Java 用 private 字段 + 公開訪問器/修改器實現封裝:
// C 結構體
struct Point { float x; float y; };
// Java 替代:不可變類模式(推薦)
public final class Point {
private final float x;
private final float y;
public Point(float x, float y) { this.x = x; this.y = y; }
public float getX() { return x; }
public float getY() { return y; }
// 可選:withX/withY 返回新實例,保持不可變性
}
優勢:類型安全、不可變性、防禦性拷貝、可添加驗證邏輯、支持 equals/hashCode/toString 契約。若必須可變,提供 setter 但需謹慎權衡線程安全。
C 聯合同一內存區域存儲不同類型數據,Java 用密封類層次(sealed classes / 訪問者模式)實現:
// C 聯合
union Shape { Circle c; Rectangle r; Square s; };
// Java 替代:抽象基類 + 具體子類
abstract class Shape { abstract double area(); }
final class Circle extends Shape { ... }
final class Rectangle extends Shape { ... }
final class Square extends Shape { ... }
// JDK 17+ 可用 sealed class Shape permits Circle, Rectangle, Square
編譯器強制窮盡匹配(switch/visitor),消除「忘記處理某類型」的運行時風險。
JDK 5.0 前無 enum 關鍵字,用「類型安全枚舉模式」模擬:
// C 枚舉
typedef enum { CIRCLE, RECTANGLE, SQUARE } Shape;
// Java 5.0 前模式
public class Shape {
private final String name;
private Shape(String name) { this.name = name; }
public String toString() { return name; }
public static final Shape CIRCLE = new Shape("CIRCLE");
public static final Shape RECTANGLE = new Shape("RECTANGLE");
public static final Shape SQUARE = new Shape("SQUARE");
}
// JDK 5.0+ 原生枚舉(強烈推薦)
public enum Shape { CIRCLE, RECTANGLE, SQUARE }
// 可攜帶字段/方法/實現接口,天然單例、可序列化、可 switch
原生枚舉編譯器生成 values()/valueOf(),支持 EnumSet/EnumMap 高效位運算,完美替代 int 常量模式。
C 函數指針傳遞行為,Java 用函數式接口(單抽象方法接口)+ Lambda(JDK 8+)實現:
// C 函數指針
int (*cmp)(void*, void*);
// Java 7 匿名內部類
Arrays.sort(arr, new Comparator
Comparator、Runnable、Callable、Function 等標準函數式接口構成行為參數化的基礎設施。
| C 構造 | Java 替代 | 關鍵優勢 |
|---|---|---|
| struct | final class + private final fields | 封裝、不可變、類型安全 |
| union | sealed class hierarchy / visitor | 窮盡匹配、編譯期檢查 |
| enum | enum (JDK 5+) / typesafe enum class | 單例、可序列化、豐富行為 |
| function pointer | functional interface + lambda | 類型推導、閉包、方法引用 |
Java 通過「類即模塊、接口即契約、枚舉即類、函數即對象」的設計哲學,將 C 的弱類型、手動內存、無名空間機制轉化為強類型、自動管理、豐富生態的現代語言特性。