Annotation

Annotation是代码里的特殊标记,这些标记可以在编译,类加载、运行时被读取,并执行相应的处理。通过使用注解,程序开发人员可以通过这些补充信息进行验证或者进行部署。


Annotation就像修饰符一样,可用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明,这些信息被存储在Annotation的"name=value"对中。

Annotation能被用来为程序元素(类、方法、成员变量)设置元数据。Annotation不影响程序代码的执行,无论是删除、增加Annotation。


基本Annotation

@Override限定重写父类方法

@Deprecated标记已过时

@SuppressWarnings(name="value")抑制编译器警告

@SafeVarargs抑制堆污染警告

堆污染是指把一个不带泛型的对象赋给一个泛型的常量

@FunctionalInterface指定某个接口必须是函数式接口(只能修饰接口)


根据Annotation是否包含成员变量,将Annotation分为如下两类:

1、标记Annotation,没有定义成员变量的Annotation类型被称为标记。

2、元数据Annotation,包含成员变量,可以接收更多的元数据。


元Annotation

@Retention指定被修饰的Annotation可以保留多长时间

@Target执行被修饰的Annotation用于修饰哪些程序单元

@Documented指定被修饰的Annotation类将被javadoc工具提取成文档,如果定义Annotation类时使用了@Documented修饰,则使用该Annotation修饰的程序元素的API文档将会包含该Annotation说明。

@Inherited指定被修饰的Annotation具有继承性,如果某个类使用了@Inheritable修饰,则该类的子类自动使用@Inheritable修饰。


自定义Annotation:

public @interface MyTag{
    String name() default "yeeku";
    int age() default 32;
}

提取Annotation信息:

java.lang.reflect包下包含实现反射功能的工具类,也增加了读取运行时Annotation的能力。只有当定义Annotation时使用了@Retention(RetentionPolicy.RUNTIME)修饰,该@Retention才会在运行时可见,JVM才会在装在*.class文件时读取保存在class文件中的Annotation。

Class<?> clazz = Class.forName("annotation.case5.Test");
Annotation[] aArrays = clazz.getMethod("info").getAnnotations();
for(Annotation an:aArrays){
    System.out.println(an);
}
for(Annotation tag:aArrays){
    if(tag instanceof MyTag){
        System.out.println(((MyTag) tag).name());
        System.out.println(((MyTag) tag).age());
    }
}


使用Annotation:

为了让Annotation起作用,要为注解提供一个注解处理工具,如果目标类使用了注解修饰,就通过反射来运行测试方法。

//定义一个标记注解
@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface Testable {
}

//使用@Testable来标记这些方法是可测试的
public class MyTest {
    @Testable
    public static void m1(){
        
    }
    
    public static void m2(){
        
    }
    
    @Testable
    public static void m3(){
        throw new IllegalArgumentException("参数出错了!");
    }
    
    public static void m4(){
        
    }
    
    @Testable
    public static void m5(){
        
    }
    
    public static void m6(){
        
    }
}

//为注解提供一个注解处理工具
public class ProcessorTest {
    public static void process(String clazz) throws ClassNotFoundException{
        int passed=0;
        int failed=0;
        
        for (Method m : Class.forName(clazz).getMethods()) {
            if(m.isAnnotationPresent(Testable.class)){
                try {
                    m.invoke(null);
                    passed++;
                } catch (Exception e) {
                    // TODO: handle exception
                    System.out.println("方法"+m+"运行失败,异常:"+e.getCause());
                    failed++;
                }
            }
        }
        System.out.println("共运行了:"+(passed+failed)+"个方法,其中:\n"+"失败了:"+failed+"个,成功了:"+passed+"个!");
    }
}

//测试主类
public class RunTests {

    public static void main(String[] args) throws ClassNotFoundException {
        // TODO Auto-generated  stub
        ProcessorTest.process("annotatiomethodn.MyTest");
    }

}


其实Annotation就是对源代码增加一些特殊标记,这些标记可通过反射获取,当程序获取这些特殊标记后,程序可以做出相应的处理。

//为程序绑定事件监听器
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionListenerFor {
	Class<? extends ActionListener> listener();
}

//测试类
<pre name="code" class="java">public class AnnotationTest {
	private JFrame mainWin=new JFrame("使用注解绑定事件监听器");
	@ActionListenerFor(listener=OkListener.class)
	private JButton ok=new JButton("确定");
	@ActionListenerFor(listener=CancelListener.class)
	private JButton cancel=new JButton("取消");

	public void init() {
		JPanel jp=new JPanel();
		jp.add(ok);
		jp.add(cancel);
		mainWin.add(jp);
		ActionListenerInstaller.processAnnotations(this);
		mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainWin.pack();
		mainWin.setVisible(true);
	}
	
	public static void main(String[] args){
		new AnnotationTest().init();
	}
}

class OkListener implements ActionListener{

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		JOptionPane.showMessageDialog(null, "单机了确认按钮");
	}
	
}

class CancelListener implements ActionListener{

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		JOptionPane.showMessageDialog(null, "单机了取消按钮");
	}
	
}

//注解处理工具
public class ActionListenerInstaller {
    public static void processAnnotations(Object object){
        Class<? extends Object> c1=object.getClass();
        System.out.println(c1.getDeclaredFields().length);
        try {
            for (Field f : c1.getDeclaredFields()) {
                f.setAccessible(true);
                ActionListenerFor a = f.getAnnotation(ActionListenerFor.class);
                Object fObject=f.get(object);
                if(a!=null&&fObject!=null&&fObject instanceof AbstractButton){
                    Class<? extends ActionListener> listenerClazz=a.listener();
                    ActionListener a1=listenerClazz.newInstance();
                    AbstractButton ab=(AbstractButton) fObject;
                    ab.addActionListener(a1);
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
} 

 
java8新增了重复注解,允许使用多个相同类型的Annotation来修饰同一个类。 

为了使注解改造成重复注解,需要使用@Repeatable来修饰该注解,还得创造一个容器注解来包含这个value();为了获取一个类中的多个Annotation注解,可以使用java8新增的getDeclaredAnnotationByType()方法:

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(FkTags.class)
@Target(ElementType.TYPE)
public @interface FkTag {
	String name() default "疯狂软件";
	int age();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FkTags {
    FkTag[] value();
}

@FkTag(age=5)
@FkTag(name="疯狂java",age=9)
public class FkTagTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Class<FkTagTest> clazz=FkTagTest.class;
        FkTag[] tags=clazz.getDeclaredAnnotationsByType(FkTag.class);
        for (FkTag fkTag : tags) {
            System.out.println(fkTag.name()+"-->"+fkTag.age());
        }
        
        FkTags container = clazz.getDeclaredAnnotation(FkTags.class);
        System.out.println(container);
    }

}

APT(Annotation Processing Tool)是一种注解处理工具,对源代码文件进行检测,并找出源文件所包含的Annotation信息,针对Annotation信息进行额外的处理。例如通过注解可以在java源文件中放置一些Annotation,使用APT工具就可以生成另一份XML文件。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值