Java注解
最近在学习Java和反射相关的知识,看到了注解的部分,感觉也是一个非常有用的部分,特意提出来记录一下。
自定义注解的定义
@Retention(RetentionPolicy.RUNTIME)
public @interface XYC {
String value();
就像类用class声明一样,注解用@interface来声明;
元注解:
在编写自定义注解的过程中,一定会或多或少的用到元注解,元注解简单的理解就是Java语言中自带的,用于定义其他注解的注解。
从JDK 1.5开始, Java增加了对元数据(MetaData)的支持,也就是 Annotation(注解)。除了直接使用JDK 定义好的注解,我们还可以自定义注解,在JDK 1.5中提供了4个标准的用来对注解类型进行注解的注解类,我们称之为 meta-annotation(元注解)
@Target
@Target注解的作用是描述注解的使用范围(注解可以用在什么地方),通过枚举,一共规定了以下的取值,
- TYPE 用于类、接口、枚举类
- FIELD 用于成员变量(枚举变量)
- METHOD 用于成员方法
- PARAMETER 用于方法参数
- CONSTRUCTOR 用于构造方法
- LOCAL_VARIABLE 用于局部变量
- ANNOTATION_TYPE 用于注解类
- PACKAGE 用于包
- TYPE_PARAMETER 类型参数 JDK1.8中新增
- TYPE_USE JDK1.8新增,用于任何地方
@Retention注解
@Retention注解的作用是: 描述注解保留的时间范围,用来限定那些被它注解的注解类在注解在其他类上以后,可被保留到何时,通过枚举规定,共 三种:
- SOURCE 源文件保留
- CLASS 编译器保留
- RUNTIME 运行期保留 通常自定义注解都是RUNTIME,可以通过注解获取注解信息
@Documented
Documented注解的作用是:描述在使用javadoc工具为类生成帮助文档时是否要保留其注解信息。
@Inherited
Inherited注解的作用是:被它修饰的注解具有继承性,如果某个类使用了这个注解,那么他的子类自动具有该注解。
自定义注解的变量
String value();
Boolean right();
和一般的类不同,自定义注解的变量是 类型 变量名();定义的变量可以通过反射取到;
自定义注解的使用
这也是我最近才研究清楚的,之前总是不明确自定义注解应该如何使用,但是在各个框架中,几乎都会用到注解。并且一般都会结合反射来使用
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Xyc {
String value();
boolean print() default false;
}
首先,定义了一个名为@Xyc的注解,这个注解有两个变量,value 和boolean类型的print变量。可以看到,在自定义注解中,并没有使用@Target注解,如果不使用Target注解,那么表示这个注解可以用在 各种地方。
我们可以定义一下逻辑:如果print为true,那么就打印一句话。
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@Xyc(value = "xyc",print = true)
public class Test {
@Xyc("xy")
private String a = "1";
private void setA(String a) {
this.a = a;
}
@Xyc("yc")
private String getA() {
return a;
}
public static void main(String[] args) {
Test test = new Test();
Class<? extends Test> aClass = test.getClass();
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
Xyc annotation = field.getAnnotation(Xyc.class);
if (annotation != null) {
boolean print = annotation.print();
if (print){
System.out.println("############################" + annotation.value());
}
}
}
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
Xyc annotation = method.getAnnotation(Xyc.class);
if (annotation != null) {
System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + annotation.value() + "!!!!!!!!!!");
}
}
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof Xyc) {
String value = ((Xyc) annotation).value();
System.out.println("xyc" + "\t" + value);
}
}
}
}
让我们运行一下:································
############################xy
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!yc!!!!!!!!!!
xyc xyc
可以看到当print为true的时候,可以成功打印。
然后新建一个Test类,在这个类中,我们使用自定义的@Xyc注解。我们在类中,方法中,和成员变量中,都使用了自定义注解。注解的使用逻辑如下:
成员变量的注解:
- 首先通过反射,获取到Test的信息;通过aClass.getDeclaredFields();可以获取到所有的成员变量(包括private修饰的成员变量);
- 然后可以遍历Field数组,通过field.getAnnotation(Xyc.class); 查找这个field(成员变量中)是否包含Xyc注解,如果有存在,则会返回注解对象。
- 判断返回的对象,是否为null,可以判断是否含有注解,并且可以通过
注解.变量名
来获取注解中的变量值。在获取到变量值后,可以根据变量值完成后续的业务逻辑,这里我们打印一句话;
方法上的注解
方法上的注解的获取方式和成员变量的注解获取方式详细,先通过反射获取到全部的Method,然后在进行针对Method判断该method是否含有注解信息,并实现后续的逻辑。
判断注解的方式:
- 可以通过
field.getAnnotation(注解.class)
或者method.getAnnotation(注解.class)
- 通过getAnnotations();获取全部的注解,然后循环注解,与想要判断的注解进行比较
instanceof
.
一般就是这两种方式来判断和获取注解。
以上大致总结了(随便写写)注解的相关知识点,以及简单的用途(当然用途不仅仅如此,有机会更)。