Java注解以及自定义注解

注解相关概念

什么是注解?
用来说明程序的一个标识,是给计算机看的。注解也叫元数据,是一种代码级别的说明。它是jdk1.5之后引入的一个特性,是一种特殊的接口。可以使用在字段、类、方法、包、参数等上面。
注意:注解本身没有任何功能,仅仅起到一个标示性的作用。我们是通过反射去获取到注解,再根据是否有这个注解、注解中的一些属性去判断执行哪种业务逻辑。


作用分类

  • 编写文档
    • 通过代码里的注解标识去生成api文档(比如swagger)
  • 代码分析
    • 通过注解去对代码进行逻辑上的分析(通过反射去操作业务)
  • 编译检查
    • 通过注解让编译器实现基本的编译检查
  • ……


注解举例

  • jdk自带的
    • @Override
    • @Deprecated
    • @SuppressWarnings
    • ……
  • spring的
    • @Component
    • @Bean
    • ……
  • ……

自定义注解

格式

public @interface 注解名称 {
    // 属性类型 属性名();
    // 或
    // 属性类型 属性名() default 默认值;
}

本质就是个接口,该接口继承自@Annotation接口

属性
接口中的抽象方法,属性只能是以下几种数据类型:

  • 基本数据类型
  • String
  • 枚举
  • 注解
  • 以上类型的数组

如果定义了属性,在使用的时候需要给属性赋值,如果有默认值可以不赋值。
如果只有一个属性需要复制,并且这个属性叫做value,那么就可以省略属性名。
数组赋值时,值用{}包裹,如果数组中只有一个值,那么{}可以省略。


元注解
元注解是用来描述注解的注解。

  • @Target:描述该注解的作用范围
    • ElementType取值:
      • TYPE:作用于类
      • METHOD:作用于方法
      • FIELD:作用于字段
  • @Retention:描述注解被保留的阶段
    • RetentionPolicy.RUNTIME:当前描述的注解,会保留到class字节码文件中,并被jvm读取到
  • @Documented:描述注解是否被抽取到api文档中
  • @Inherited:描述注解是否可以被继承

简单案例

定义一个我们自己的注解 @MyAnnocation
MyAnnocation.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 说明使用在 类、接口(包括注释类型)、枚举声明  或者 字段上
@Target({ElementType.TYPE, ElementType.FIELD})
// 注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射方式读取它们
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnocation {
    String value();

    int num() default 1;
}

为什么value和num都会有括号()呢?
实际上任何注解本身都是接口 ,只不过是隐式继承了Annotation这个接口而已。
image.png
Annotation 是jdk1.5 新增的,然而接口定义方法体是jdk1.8才有的特性,而且必须显式定义为default 修饰的普通方法 或者 静态方法。
所以我们定义的注解都算是接口,所以不允许存在方法体。


定义一个测试用到的实体类User,并加上我们自定义的注解
User.java

/**
 * @Auth: guohui.wang
 * @Date: 2021-03-25 17:42
 * @desc:
 */
/*
    值为value的字段可以省略 value= ,直接写值。
    但是如果设置多个值得时候就需要全都写上了,比如:
    @MyAnnocation("用户")
    @MyAnnocation(value = "用户")
    @MyAnnocation(value = "用户",num = 1)
 */
@MyAnnocation("用户")
public class User {
    @MyAnnocation("快乐码农盒")
    private String username;

    @MyAnnocation
    private int age;

    private int sex;

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}

然后创建一个测试类Test进行我们自定义注解的测试
Test.java

import java.lang.reflect.Field;

/**
 * @Auth: guohui.wang
 * @Date: 2021-03-25 17:43
 * @desc:
 */
public class Test {
    public static void main(String[] args) throws Exception {
       /*
            test1()结果:
            annotation.value is : 用户
            annotation.num is : 1
        */
        test1();
        /*
            test2()结果:
            User{username='快乐码农盒', age=1, sex=0}
         */
        test2();
    }

    /**
     * 获取类上面标注的注解
     */
    public static void test1() {
        Class<User> userClass = User.class;
        MyAnnocation annotation = userClass.getAnnotation(MyAnnocation.class);
        if (annotation != null) {
            System.out.println("annotation.value is : " + annotation.value());
            System.out.println("annotation.num is : " + annotation.num());
        }
    }

    /**
     * 获取字段上面标注的注解
     * 并将注解的值赋值给对应字段
     */
    public static void test2() throws IllegalAccessException {
        User user = new User();
        // 获取Class对象
        Class<User> userClass = User.class;
        // 获取所有字段,括公共,受保护,默认(程序包)访问和私有字段,但不包括继承的字段。
        Field[] fields = userClass.getDeclaredFields();
        // 对所有字段遍历通过添加的注解对应赋值
        for (Field field : fields) {
            MyAnnocation annotation = field.getAnnotation(MyAnnocation.class);
            if (annotation != null) {
                // 设置禁止Java语言访问检查,暴力访问
                field.setAccessible(true);
                // 对标注注解的字段赋值注解中对应类型的值
                if (field.getType() == String.class) {
                    String value = annotation.value();
                    field.set(user, value);
                } else if (field.getType() == int.class) {
                    int num = annotation.num();
                    field.set(user, num);
                }
            }
        }
        System.out.println(user);
    }
}

执行结果:
image.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值