匿名类对象,最常见的是通过直接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) 执行");
}
};
}