Java基础——注解的艺术

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行,只有publicdefault这两种访问权限,不加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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉淀顶峰相见的PET

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值