匿名類對象,最常見的是通過直接new一個接口,並實現接口中的方法來創建。在註冊swing或者swt控件的事件監聽器的時候,我們經常通過創建匿名對象的方式避免創建新的類來繼承Adapter抽象類或者實現Listener接口,例如:
NewGame.addSelectionListener(new SelectionAdapter() { // SelectionAdapter是一個抽象類
@Override
public void widgetSelected(SelectionEvent e) {
}
});
現在假設有這樣的代碼,我希望在匿名類對象的方法上,添加一個名爲@EventMusic的註解,可以標記事件發生的時候的音樂。可以寫這樣的代碼:
public class MainWin extends ApplicationWindow {
// ……
public static void main(String args[]) {
Class<?> cmw = MainWin.class;
Field ngc = cmw.getDeclaredField("NewGameClick");
Class<?> cListener = ngc.getType();
Method[] methods = cListener.getMethods();
for(Method method : methods)
{
Annotation[] anns = method.getAnnotations();
for(Annotation ann : anns) System.out.println(ann.toString());
}
}
private SelectionListener NewGameClick = new SelectionAdapter() {
@Override
@EventMusic("doubleclick")
public void widgetSelected(SelectionEvent arg0) {
System.out.println("public void widgetSelected(SelectionEvent) 執行");
}
};
}
註解@EventMusic的代碼:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface EventMusic{
public String value();
}
我們知道,註解的定義本身不實現任何的功能,註解的功能都是靠其他代碼通過反射檢測到註解之後,再根據註解的含義去做相應的處理的。所以,main函數的代碼嘗試去獲取NewGameClick對象裏的所有方法上的註解,然後把名稱輸出出來。遺憾的是,這樣的代碼你永遠都看不到輸出的內容裏有@EventMusic,明明@EventMusic的定義裏設置了@Retention(RetentionPolicy.RUNTIME),也就是在運行時能夠通過反射檢測到,爲什麼又會拿不到呢?
MainWin window = new MainWin();
Class<?> cmw = MainWin.class;
Field ngc = cmw.getDeclaredField("NewGameClick");
Class<?> cListener1 = ngc.getType();
Class<?> cListener2 = ngc.get(window).getClass(); // 取回NewGameClick這個對象再調用它的getClass方法
Class<?> cListener3 = SelectionListener.class;
boolean one_two = cListener1.equals(cListener2); // false
boolean one_three = cListener1.equals(cListener3); // true
這時候就很明白了,遇到匿名類對象,必須通過它的getClass方法才能拿到匿名類的Class,通過Field.getType獲取到的只是原來的接口或者抽象類的Class,所以用原來的接口或者抽象類的Class又怎麼可能拿到匿名類的方法的註解呢。最後給出可以拿到@EventMusic的代碼:
public class MainWin extends ApplicationWindow {
// ……
public static void main(String args[]) {
MainWin window = new MainWin();
Class<?> cmw = MainWin.class;
Field ngc = cmw.getDeclaredField("NewGameClick");
Class<?> cListener = ngc.get(window).getClass(); // 拿到對象再調用對象的getClass獲取匿名類的Class
Method[] methods = cListener.getMethods();
for(Method method : methods)
{
Annotation[] anns = method.getAnnotations();
for(Annotation ann : anns) System.out.println(ann.toString());
}
}
private SelectionListener NewGameClick = new SelectionAdapter() {
@Override
@EventMusic("doubleclick")
public void widgetSelected(SelectionEvent arg0) {
System.out.println("public void widgetSelected(SelectionEvent) 執行");
}
};
}