從簡單的固定順序參數,到可選參數、默認值、任意順序、幫助資訊,命令行解析邏輯隨專案增長而膨脹。反射能將「參數定義」與「解析邏輯」分離,讓應用僅聲明字段與標記對應,庫自動完成賦值。
boolean、int、float、String 等常見類型。-c -f2500 -g2.5 -n "name" output.txt(單字母標記,值緊跟或空格分隔)。基類 ParameterDef 封裝標記字符、字段名、反射綁定邏輯:
public abstract class ParameterDef {
protected char flag; protected String fieldName; protected Field field;
protected ParameterDef(char flag, String fieldName) { this.flag = flag; this.fieldName = fieldName; }
protected void bindToClass(Class clazz) {
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Field '" + fieldName + "' not found in " + clazz.getName());
}
}
public abstract void handle(ArgumentProcessor processor);
}
子類如 BoolDef、IntDef(含範圍檢查)、FloatDef、StringDef 實現具體解析與賦值。
public class PlanGen {
private boolean concise;
private int initialRevenue = 1000;
private float growthRate = 1.5f;
private String productDescription = "Default";
private static final ParameterDef[] DEFS = {
new BoolDef('c', "concise"),
new IntDef('f', "initialRevenue", 10, 10000),
new FloatDef('g', "growthRate", 1.0f, 100.0f),
new StringDef('n', "productDescription")
};
public static void main(String[] args) {
if (args.length == 0) { printUsage(); return; }
PlanGen inst = new PlanGen();
int next = ArgumentProcessor.processArgs(args, DEFS, inst);
if (next >= args.length) { System.err.println("Missing output file"); System.exit(1); }
File out = new File(args[next]);
// 業務邏輯...
}
}
bindToClass),提早暴露拼錯字段名等錯誤。args,識別標記,委派給對應 ParameterDef.handle()。setValue(Object, Field) 統一透過反射賦值。測試顯示整個解析流程平均僅增加 40 毫秒,主要耗於類載入,對命令行工具完全可接受。庫已開源,支援自動生成幫助資訊、必選參數檢查等擴展。
前三部分奠定了類結構、反射基礎。第 4 部分將引入 Javassist,展示如何直接修改二進制類實現更深層的動態行為。