Java注解
因为本篇文章我选择的是自定义注解来是实现切面的功能,所以先来带大家来看看Java提供的一些元注解,这些元注解是注解自定义注解很重要的一部分
元注解
java提供的java.lang.annotation
包里给大家提供了这些元注解,今天要给你们讲的也是比较重要的四个,我都给大家框起来了,这四个元注解就是用来注解自定义注解的
也就是说几乎每个注解都要用到元注解
我来给大家逐个分析这些元注解的作用以及含义
@Documented
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
该注解用于描述其它类型的注解是否应该使用@API标注出来,如果使用了@Documented
注解,在生成javadoc时就会把其它的注解以@API
的形式表现出来,自定义注解非必须,是一个标注注解
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
当自定义注解使用@Inherited
时,自定义注解所作用的类为它的子类,并不直接作用于自定义注解标注的类
当@Inherited
与@Retention
作用于一个注解且@Retention
的属性定义为RetentionPolicy.RUNTIME
,会增强反射获取注解的深度,例如我一般使用反射去获取一个类的注解时,如下代码
Annotation[] annotations1 = Man.class.getDeclaredAnnotations();
我获取到的只能是这个类的注解,但是我这个类是继承于另一个类的,我还想获得其父类的注解怎么办呢?在父类作用的自定义注解上加入@Inherited
即可,也可以先获取父类的class对象再去反射注解也行,我这里只是提供一个方法
@Retention
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
@Retention
其实就是对其作用注解的一个生命周期的限制,有三种方式来定义,分别对应.java文件
-> .class文件
-> 内存字节码文件
第一种,RetentionPolicy.SOURCE
,该属性表示使用@Retention
注解定义的自定义注解只会在源文件里保留,不会加载到class文件中
第二种,RetentionPolicy.CLASS
,表示在class文件中可以查看到自定义注解,但是jvm加载class文件时会将自定义注解丢弃,这是默认的情况
第三种,RetentionPolicy.RUNTIME
,表示jvm在加载class文件会将注解保存,并不会丢弃
@Target
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
@Target
用来标注自定义注解所作用的范围,该作用的返回为java.lang.annotation
包中定义的一个枚举类ElementType
public enum ElementType {
/** 用于描述类、接口(自定义注解等)、枚举声明 */
TYPE,
/** 字段(类成员变量)声明(包括枚举常量) */
FIELD,
/** 方法声明 */
METHOD,
/** 用于形式参数声明 */
PARAMETER,
/** 构造方法声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包声明 */
PACKAGE,
/**
* 类型参数声明
*
* java 8 之后可用
*/
TYPE_PARAMETER,
/**
* 所使用类型
*
* @since 1.8
*/
TYPE_USE
}
通过上面的声明,我们就可以控制自定义注解所作用的范围
上面就是我们四个比较重要的元注解的讲解了,现在我们来自定义几个注解来试试
自定义注解语法
标准语法:
public @interface 注解名称 {
//注解参数
}
注解参数支持的数据类型:
八大基本数据类型、引用数据类型(String、class、枚举、注解(Annotation)等),以及以上类型的数组形式,下面为示例
@Target(ElementType.FIELD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface peopleName {
public String name() default "ALiangX";
}
第1行,ElementType.FIELD
表示该注解只能作用于类成员变量
第2行,标记注解,javadoc生成所使用注解的@API,标记注解
第3行,RetentionPolicy.RUNTIME
,表示注解在运行时也可以生效
第4行,注解名称为peopleName
第5行,只有public
和default
这两种访问权限,不加public
默认为default
String
表示属性的类型
name()
表示属性名称
default "ALiangX"
表示属性的默认值为ALiangX,默认值类型必须与属性类型一样
自定义注解(实战)
新建People类
import lombok.Data;
@Data
@peopleClass(value = "Test ElementType.TYPE")
public class People {
@peopleName
private String name;
@peopleSex(sex = peopleSex.sex.WOMAN)
public String sex;
@peopleAge(age = 22)
private int age;
@peopleAddress(address = "中国·山东·济南")
public String address;
public People() {
}
public People(String name, String sex, int age, String address) {
this.name = name;
this.sex = sex;
this.age = age;
this.address = address;
}
}
针对4个属性分别新建4个注解和一个类注解,我直接上代码
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface peopleClass {
public String value();
}
@Target(ElementType.FIELD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface peopleName {
public String name() default "ALiangX";
}
@Target(ElementType.FIELD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface peopleSex {
public enum sex{MAN,WOMAN}
public sex sex() default sex.MAN;
}
@Target(ElementType.FIELD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface peopleAge {
public int age() default 20;
}
@Target(ElementType.FIELD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface peopleAddress {
public String address() default "";
public String phone() default "17866668888";
}
将注解绑定到属性上就可以,那我们要怎么在运行时获取到这些注解所赋予类属性的值呢?这就要利用到反射的知识了,不知道反射的小伙伴可以去看看我这篇文章 Java基础——反射有多强,用过才知道
通过反射可以获取类在运行时的注解,直接上代码
package Basics.Annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
public class Test_annotation {
public static void main(String[] args) throws NoSuchMethodException {
People people = new People();
Class peopleClass = people.getClass();
//获取类上的注解
Annotation[] annotationsClass = peopleClass.getAnnotations();
for(Annotation annotation : annotationsClass){
//获取类注解
System.out.println("类注解:" + annotation + "\n");
}
//获取类属性上的注解
//先获取属性
Field[] fields = peopleClass.getDeclaredFields();
for(Field field : fields){
System.out.println("属性名称:" + field.getName());
Annotation[] annotations = field.getDeclaredAnnotations();
for(Annotation annotation : annotations){
System.out.println("属性对应的注解:" + annotation + "\n");
}
}
//获取类方法上的注解
// Method[] methods = peopleClass.getDeclaredMethods();
// for(Method method : methods){
// System.out.println(method.getName());
// Annotation[] annotations = method.getDeclaredAnnotations();
// for(Annotation annotation : annotations){
// System.out.println("方法对应的注解:" + annotation + "\n");
// }
// }
}
}
运行结果:
这样我们就可以在程序运行的过程中获取到注解(名称、属性)等字段来进行下一步的业务逻辑
下一篇我们将结合注解来实现spring boot的AOP切面编程
转载请标注原作者,谢谢你们的支持,能给个小心心吗?
完成:2021/4/04 17:02 ALiangXLogic