有两种特殊的快捷方式可以用来简化注解的使用
* 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
该实例演示了注解的相关操作