你可以使用反射動態載入.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;
}
}
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));
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);
}
}
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("誰在呱呱叫");
}
});
public void quack() {
System.out.println("誰在呱呱叫");
}
});
不過模彷鴨子類型並不是沒有代價,也就是要付出效能作為補償(根據實際的需求,也許你可分析看看,是否有哪些Method等反射物件可以快取,不用每次都動態生成,藉此改進一些效能)。