import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
//(元注释后面讲)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) //定义作用在字段上
@Documented
@interface ActionListenerAnno {
//该listener成员变量用于保存监听器实现类
Class<? extends ActionListener> listener();
}
public class TestListener {
JFrame jf = new JFrame("测试");
@ActionListenerAnno(listener=OkListener.class)
private JButton ok = new JButton("确认");
@ActionListenerAnno(listener=CancelListener.class)
private JButton cancel = new JButton("取消");
public void init() throws IllegalArgumentException, IllegalAccessException, InstantiationException{
JPanel jp = new JPanel();
jp.add(ok);
jp.add(cancel);
jf.add(jp);
//添加监听器
ButtonActionListener.process(this);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
jf.setLocationRelativeTo(null);
jf.setVisible(true);
}
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
new TestListener().init();
}
}
class OkListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("确认按钮被点击");
JOptionPane.showMessageDialog(null, "确认按钮被点击");
}
}
class CancelListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("取消按钮被点击");
JOptionPane.showMessageDialog(null, "取消按钮被点击");
}
}
class ButtonActionListener{
public static void process(Object obj) throws IllegalArgumentException, IllegalAccessException, InstantiationException{
Class<? extends Object> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
//将指定Field设置成可自由访问的,避免private的Field不能访问
f.setAccessible(true);
//获取指定Field的ActionListenerAnno类型的注解
ActionListenerAnno a = f.getAnnotation(ActionListenerAnno.class);
// 获取成员变量f的值
Object fObj = f.get(obj);
if(a != null && fObj instanceof AbstractButton){
// 获取a注解里的listner元数据(它是一个监听器类)
Class<? extends ActionListener> listenerClazz = a.listener();
// 使用反射来创建listner类的对象
ActionListener al = listenerClazz.newInstance();
AbstractButton ab = (AbstractButton)fObj;
// 为ab按钮添加事件监听器
ab.addActionListener(al);
}
}
}
}
-
JDK的元Annotation
JDK除了在java.lang 下提供了3个基本Annotation之外,还在java.lang.annotation包下提供了四个Meta Annotation(元Annotation),这四个Annotation都是用于修饰其他Annotation定义。
-
使用@Retention
@Retention只能用于修饰一个Annotation定义,用于指定该Annotation可以保留多长时间,@Retention包含一个RetentionPolicy类型的value成员变量,所以使用@Retention时必须为该value成员变量指定值。
value成员变量的值只能是如下三个:
-
- RetentionPolicy.CLASS: 编译器将把注释记录在class文件中。当运行Java程序时,JVM不在保留注释,这是默认值。
- RetentionPolicy.RUNTIME: 编译器将把注释记录在class文件中。当运行Java程序时,JVM也会保留注释,程序可以通过反射获取该注释。
- RetentionPolicy.SOURCE: 注解仅存在于源码中,在class字节码文件中不包含。
-
使用@Target
@Target也是用于修饰一个Annotation定义,它用于指定被修饰Annotation能用于修饰那些程序元素。@Target Annotation也包含一个名为value的成员变量,该成员变量只能是如下几个:
-
- ElementType.ANNOTATION_TYPE: 指定该策略的Annotation只能修饰Annotation。
- ElementType.CONSTRUCTOR: 指定该策略的Annotation能修饰构造器。
- ElementType.FIELD: 指定该策略的Annotation只能修饰成员变量。
- ElementType.LOCAL_VARIABLE: 指定该策略的Annotation只能修饰局部变量。
- ElementType.METHOD: 指定该策略的Annotation只能修饰方法。
- ElementType.PACKAGE: 指定该策略的Annotation只能修饰包定义。
- ElementType.PARAMETER: 指定该策略的Annotation可以修饰参数。
- ElementType.TYPE: 指定该策略的Annotation可以修饰类、接口(包括注释类型)或枚举定义。
-
使用@Documented
@Documented用于指定该元Annotation修饰的Annotation类将被javadoc工具提取成文档,如果定义Annotation类时使用了@Documented修饰,则所有使用该Annotation修饰的程序元素的API文档中将会包含该Annotation说明。
-
使用@Inherited
@Inherited 元 Annotation指定被它修饰的Annotation将具有继承性:如果某个类使用了A Annotation(定义该Annotation时使用了@Inherited修饰)修饰,则其子类将自动具有A注释。