Java自定义注解与注解处理器(二)

有两种特殊的快捷方式可以用来简化注解的使用
     * 1.如果注解中没有元素,或者所有元素都使用了默认值,那么在使用注解时就不需要使用
     * 圆括号和指定元素了,没有使用任何元素的注解,我们称之为标记注解(market annotation)
     * 例如Override注解
     * 2.另外一种快捷方式是单值注解,如果一个元素具有特殊的名字value,并且没有指定其他元素,那么在使用注解时可以
     * 省略元素名和等号,直接给出元素的值; 例如:
     *
     * public @interface BugReport{
     *     String value();
     * }

(一)注解与反射

你是否有疑问,自定义的注解到底有什么用?如果你只是定义了注解,用注解去做标记,那确实没有什么用。 要想让注解正真起作用, 还需要编写程序对标记后的注解进行解析,根据注解的含义做出相应的动作。 

要解析注解,自然要先得到注解的信息,在反射API中,定义了AnnotatedElement接口,在该接口中给出了得到注解的方法。
* Class,Constructor,Field,Method等可以用注解标记的程序元素都实现了AnnotatedElement接口,便于获取其上存在的注解。
* 也就是说Class,Constructor,Field,Method等类都实现了AnnotatedElement中的接口,因此调用对应的方法就可以获得相关的注解信息;

下面是AnnotationElement接口中常用方法:
     *     (1) default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
     *     判断此元素上是否存在指定类型(就是参数指定的类型)的注解。这个方法主要是为了方法访问标记注解而给出的。当这个方法返回true时,相当于:
     *     getAnnotation(annotationClass) != null;
     *     (2) <T extends Annotation>T getAnnotation(Class<T> annotationClass) 如果此元素上不存在指定类型的注解,这返回它,如果不存在,
     *     则返回null。
     *     (3)Annotation[] getAnnotations()返回此元素上存在的所有注解,包括继承得到的注解。如果没有注解,则返回长度为0的数值;
     *     (4)default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) 这是Java 8新增的方法,
     *      由于获取与该程序元素关联的注解.这个方法与getAnnotation的区别是,它可以返回重复的注解。如果没有与此元素关联的注解,则返回长度为0的数组;
     *     (5)default <T extends Annotation> T[] getDeclaredAnnotation(Class<T> annotationClass)如果在此元素上直接存在指定类型的注解,
     *     这返回它,否则,返回null,这个方法忽略继承的注解;
     *     (6)default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
     *     这是Java8新增的方法。如果指定的类型的注解直接存在或间接存在,则返回此元素的注解. 这个方法忽略继承的注解。
     *     这个方法与getDeclaredAnnotationsByType(Class<T> annotationClass)区别是,它可以返回重复的注解。如果在此元素上没有直接或间接存在的指定注解,
     *     则返回长度为0的数组。
     *     (7) Annotation[] getDeclaredAnnotations();
     *     返回直接存在于此元素上的注解。这个方法忽略继承的注解,如果在此元素上没有存在的注解。如果在此元素上没有直接存在的注解,则返回长度0的数组;)

================================================================================

(二)注解实例的演示:

 2.1定义注解

package org.jy.sso.cas.data.server.system;

import java.lang.annotation.*;

/**
 *  * 在该注解中可以有元素,每个元素声明都具有下面两种形式
 *  * type elementName();
 *  * 或者
 *  * type elementName() default value;
 */
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD}) // 可以使用在多个地方
@Retention(RetentionPolicy.RUNTIME)
@Inherited // 注解可继承
public @interface EmBugReport {
    // default关键字用于指定元素的默认值
    public int severity() default 0;
    public String msg();
    /**
     *(1)当定义好注解后,就可以使用这个注解来进行标记。注解的使用格式为:
     * @AnnotationName(elementName1 = value1,elementName2 = value2,...)
     *
     * (2)例如:
     * @BugReport(msg ="普通bug")
     * void test1(){}
     *
     * @BugReport(severity=1,msg ="较为严重的Bug")
     * void test2()
     *
     * (3)如果注解有元素,且没有默认值,那么在使用注解时,必须要给元素赋值。
     * 有两种特殊的快捷方式可以用来简化注解的使用
     * 1.如果注解中没有元素,或者所有元素都使用了默认值,那么在使用注解时就不需要使用
     * 圆括号和指定元素了,没有使用任何元素的注解,我们称之为标记注解(market annotation)
     * 例如Override注解
     * 2.另外一种快捷方式是单值注解,如果一个元素具有特殊的名字value,并且没有指定其他元素,那么在使用注解时可以
     * 省略元素名和等号,直接给出元素的值; 例如:
     *
     * public @interface BugReport{
     *     String value();
     * }
     * 3.在使用时,可以直接写为: @BugReport("发生了bug")
     * 要注意的是,注解元素的类型时有限制的,只能使用如下的类型
     * 基本数据类型
     * String 类型
     * Class 类型
     * enum (枚举)类型
     * Annotation类型
     * 以上类型的数组
     *
     */
}

2.2 使用定义的注解标记

package org.jy.sso.cas.data.server.system.bugreport;

import org.jy.sso.cas.data.server.system.EmBugReport;

@EmBugReport(msg = "报告基类Bug")
public class Base {
    /**
     * 要解析注解,自然要先得到注解的信息,在反射API中,定义了AnnotatedElement接口,在该接口中给出了得到注解的方法。
     * Class,Constructor,Field,Method等可以用注解标记的程序元素都实现了AnnotatedElement接口,便于获取其上存在的注解。
     * 也就是说Class,Constructor,Field,Method等类都实现了AnnotatedElement中的接口,因此调用对应的方法就可以获得相关的注解信息;
     *
     * 下面是AnnotationElement接口中常用方法:
     *     (1) default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
     *     判断此元素上是否存在指定类型(就是参数指定的类型)的注解。这个方法主要是为了方法访问标记注解而给出的。当这个方法返回true时,相当于:
     *     getAnnotation(annotationClass) != null;
     *     (2) <T extends Annotation>T getAnnotation(Class<T> annotationClass) 如果此元素上不存在指定类型的注解,这返回它,如果不存在,
     *     则返回null。
     *     (3)Annotation[] getAnnotations()返回此元素上存在的所有注解,包括继承得到的注解。如果没有注解,则返回长度为0的数值;
     *     (4)default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) 这是Java 8新增的方法,
     *      由于获取与该程序元素关联的注解.这个方法与getAnnotation的区别是,它可以返回重复的注解。如果没有与此元素关联的注解,则返回长度为0的数组;
     *     (5)default <T extends Annotation> T[] getDeclaredAnnotation(Class<T> annotationClass)如果在此元素上直接存在指定类型的注解,
     *     这返回它,否则,返回null,这个方法忽略继承的注解;
     *     (6)default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
     *     这是Java8新增的方法。如果指定的类型的注解直接存在或间接存在,则返回此元素的注解. 这个方法忽略继承的注解。
     *     这个方法与getDeclaredAnnotationsByType(Class<T> annotationClass)区别是,它可以返回重复的注解。如果在此元素上没有直接或间接存在的指定注解,
     *     则返回长度为0的数组。
     *     (7) Annotation[] getDeclaredAnnotations();
     *     返回直接存在于此元素上的注解。这个方法忽略继承的注解,如果在此元素上没有存在的注解。如果在此元素上没有直接存在的注解,则返回长度0的数组;
     */
}


package org.jy.sso.cas.data.server.system.bugreport;

import org.jy.sso.cas.data.server.system.EmBugReport;

/**
 * 在Listener中使用@Repeatable注解,否则该处会报错
 */
@Listener(value = "ActionListener")
@Listener("WindowListener")
public class Derived extends Base{

    @EmBugReport(severity = 1,msg = "name字段Bug")
    private String name;
    @EmBugReport(severity = 2,msg="action方法的Bug")
    private void action(){}
}

2.3 注解处理器

package org.jy.sso.cas.data.server.system.bugreport;

import org.jy.sso.cas.data.server.system.EmBugReport;
import sun.reflect.annotation.AnnotationType;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 注解处理器
 */
public class ReflectAndAnnotationHandler {

    public static void handlerReflectAndAnnotation(Class<?> clazz) { // 不确定的类型
        Annotation[] annotations = clazz.getAnnotations();
        System.out.println("===========================(一)<Deverity>类上的注解:========================================");
        for (Annotation annotation : annotations) {
            // 得到注解的类型
            Class annotationClz = annotation.annotationType();
            //System.out.println("===================================" + annotationClz);
            if (EmBugReport.class.equals(annotationClz)) {
                EmBugReport emBugReport = (EmBugReport) annotation;
                // 获得注解中的元素值,就行调用普通方法一样
                System.out.println("(1)这个注解类型为[EmBugReport.class]: :" + EmBugReport.class);
                System.out.println("-----元素: severity = " + emBugReport.severity() + ",msg = " + emBugReport.msg());
            } else if (Listeners.class.equals(annotationClz)) {
                Listeners listeners = (Listeners) annotation;
                Listener[] listener = listeners.value();
                System.out.println("(2)这个注解类型为[Listeners.class]: :" + Listeners.class);
                for (Listener lis : listener) {
                    System.out.println("---元素: value=" + lis.value());
                }
            } else {

            }
        }
        System.out.println();
        System.out.println("===========================(二)<Deverity>类的字段上的注解:========================================");
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(EmBugReport.class)) { // 判断field上是否存在指定的EmBugReport注解
                System.out.println("字段为: field = " + field);
                EmBugReport emBugReport = field.getDeclaredAnnotation(EmBugReport.class);
                System.out.println("该字段上的注解(annotation)为 = " + emBugReport);
                System.out.println("该注解类型为: " + emBugReport.annotationType());
                System.out.println("该注解的元素: severity = " + emBugReport.severity() + ", msg = " + emBugReport.msg());
            }

        }
        System.out.println();
        System.out.println("===========================(三)<Deverity>类的方法上的注解:========================================");
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(EmBugReport.class)) { // 判断方法上是否有指定的注解
                EmBugReport emBugReport = method.getAnnotation(EmBugReport.class);
                System.out.println("方法为 = " + method.getName());
                System.out.println("方法()上的注解为 = " + emBugReport);
                System.out.println("注解的类型为: "+emBugReport.annotationType());
            }
        }


    }
}

(四) 运行该解析器

package org.jy.sso.cas.data.server.system.bugreport;

public class ReflectAndAnnotationRun {
    public static void main(String[] args){
        ReflectAndAnnotationHandler.handlerReflectAndAnnotation(Derived.class);
    }
}

输出如下结果:

==========================(一)<Deverity>类上的注解:========================================
(1)这个注解类型为[EmBugReport.class]: :interface org.jy.sso.cas.data.server.system.EmBugReport
-----元素: severity = 0,msg = 报告基类Bug
(2)这个注解类型为[Listeners.class]: :interface org.jy.sso.cas.data.server.system.bugreport.Listeners
---元素: value=ActionListener
---元素: value=WindowListener

===========================(二)<Deverity>类的字段上的注解:========================================
字段为: field = private java.lang.String org.jy.sso.cas.data.server.system.bugreport.Derived.name
该字段上的注解(annotation)为 = @org.jy.sso.cas.data.server.system.EmBugReport(severity=1, msg=name字段Bug)
该注解类型为: interface org.jy.sso.cas.data.server.system.EmBugReport
该注解的元素: severity = 1, msg = name字段Bug

===========================(三)<Deverity>类的方法上的注解:========================================
方法为 = action
方法()上的注解为 = @org.jy.sso.cas.data.server.system.EmBugReport(severity=2, msg=action方法的Bug)
注解的类型为: interface org.jy.sso.cas.data.server.system.EmBugReport

该实例演示了注解的相关操作

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值