Java获取匿名类对象(通过new接口、抽象类等方式创建)的方法上的注解
2017-12-30 16:24
471 查看
匿名类对象,最常见的是通过直接new一个接口,并实现接口中的方法来创建。在注册swing或者swt控件的事件监听器的时候,我们经常通过创建匿名对象的方式避免创建新的类来继承Adapter抽象类或者实现Listener接口,例如:
现在假设有这样的代码,我希望在匿名类对象的方法上,添加一个名为@EventMusic的注解,可以标记事件发生的时候的音乐。可以写这样的代码:
注解@EventMusic的代码:
我们知道,注解的定义本身不实现任何的功能,注解的功能都是靠其他代码通过反射检测到注解之后,再根据注解的含义去做相应的处理的。所以,main函数的代码尝试去获取NewGameClick对象里的所有方法上的注解,然后把名称输出出来。遗憾的是,这样的代码你永远都看不到输出的内容里有@EventMusic,明明@EventMusic的定义里设置了@Retention(RetentionPolicy.RUNTIME),也就是在运行时能够通过反射检测到,为什么又会拿不到呢?
其实原理很简单,上面的main函数的代码,获取的不是NewGameClick对象的widgetSelected方法上的注解,而是SelectionListener接口的widgetSelected方法上的注解。那位说,这不一样吗?答:不一样。如果SelectionListener是一个类,NewGameClick是它的对象,那么上面main函数的代码没问题。但是SelectionListener是接口,NewGameClick是它的一个匿名类对象,差别就在这里。SelectionListener是一种类型;而创建出对象的匿名类,即使是匿名的,也是与SelectionListener是不一样的类型,也就是说SelectionListener.class.equals(NewGameClick.getClass())的结果是flase。可以用如下的代码检验:
这时候就很明白了,遇到匿名类对象,必须通过它的getClass方法才能拿到匿名类的Class,通过Field.getType获取到的只是原来的接口或者抽象类的Class,所以用原来的接口或者抽象类的Class又怎么可能拿到匿名类的方法的注解呢。最后给出可以拿到@EventMusic的代码:
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),也就是在运行时能够通过反射检测到,为什么又会拿不到呢?
其实原理很简单,上面的main函数的代码,获取的不是NewGameClick对象的widgetSelected方法上的注解,而是SelectionListener接口的widgetSelected方法上的注解。那位说,这不一样吗?答:不一样。如果SelectionListener是一个类,NewGameClick是它的对象,那么上面main函数的代码没问题。但是SelectionListener是接口,NewGameClick是它的一个匿名类对象,差别就在这里。SelectionListener是一种类型;而创建出对象的匿名类,即使是匿名的,也是与SelectionListener是不一样的类型,也就是说SelectionListener.class.equals(NewGameClick.getClass())的结果是flase。可以用如下的代码检验:
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) 执行"); } }; }
相关文章推荐
- MyBatis+Spring在注解@Autowried后通过反射的方式调用方法获取注入的Service或DAO对象为空
- Java中通过注解+反射拿到对象的属性和方法
- Java反射之通过反射获取一个对象的方法信息
- java中通过放射机制创建对象的两种方式
- java中反射机制通过字节码文件对象获取字段和函数的方法
- java通过Annotation对象获取注解属性的值
- Java反射之通过反射获取一个对象的方法信息(实例代码)
- java中通过放射机制创建对象的两种方式
- java通过反射+注解获取两个对象改变的内容
- Java反射获取对象VO的属性值(通过Getter方法)
- Java反射02 : Class对象获取的三种方式和通过反射实例化对象的两种方式
- java通过读取本地文件获取反射方法参数,执行对象方法
- 6.通过反射动态创建对象,获取属性,获取方法
- java中反射机制通过字节码文件对象获取字段和函数的方法
- Java中创建对象的5种方式 &&new关键字和newInstance()方法的区别
- 通过反射可以获取Class的构造方法 通过构造方法创建对象
- 抽象类如何通过本类方法获取对象
- Java中通过Class类获取Class对象的方法详解
- spring学习(五)—通过注解方式创建对象和注入属性
- ndk多线程需要获取JNIEnv 或c通过类名+包名创建对象使用如下方法