|
|
你可以使用反射動態載入.class,從中擷取類別資訊,也可以直接利用載入的.class之Class實例,動態生成物件,更可以進一步操作物件的方法。 例如,若有個Student: package cc.openhome;
public class Student { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setScore(int score) { this.score = score; } public int getScore() { return score; } } 以下的程式可以動態生成Student實例,並透過setName()設定名稱,用getName()取得名稱,一切都是以Object型態操作,不用使用轉型: Class clz = Class.forName("cc.openhome.Student");
Constructor constructor = clz.getConstructor(new Class[] {String.class, Integer.TYPE}); Object obj = constructor.newInstance(new Object[] {"caterpillar", new Integer(90)}); Method setter = clz.getMethod("setName", new Class[] {String.class}); setter.invoke(obj, new Object[] {"caterpillar"}); Method getter = clz.getMethod("getName", null); System.out.println(getter.invoke(obj, null)); 這很有趣,這表示,你可以實現動態語言中經常出現的 鴨子類型 概念:如果它走路像隻鴨子,叫聲像個鴨子,游起來像個鴨子,那它就是鴨子。 聽來很怪?尤其是你對動態語言沒概念的話,那麼,考慮一個情況,你會有個物件,它是什麼類別你一無所知,它會實作哪些介面你也不知道,你只知道它上頭會有個quack()方法,那該怎麼寫程式來呼叫執行這個方法?可以如下: class Dog {
public void quack() { System.out.println("狗兒呱呱叫"); } } public class Main { public static void main(String[] args) throws Exception { doQuack(new Dog()); } public static void doQuack(Object duck) throws Exception { Method quack = duck.getClass().getMethod("quack", null); quack.invoke(duck, null); } } doQuack()才不管丟進來的是阿貓還是阿狗,反正它會呱呱叫就好了!就算只是個Object也無所謂: doQuack(new Object() {
public void quack() { System.out.println("誰在呱呱叫"); } }); 不過模彷鴨子類型並不是沒有代價,也就是要付出效能作為補償(根據實際的需求,也許你可分析看看,是否有哪些Method等反射物件可以快取,不用每次都動態生成,藉此改進一些效能)。 |