Java注解-最通俗易懂的讲解

注解的重要性就不用我来说了,controller层有@controller注解,service层有@service注解,基本上到处都是注解,任何一个Java框架都是通过注解+反射来实现的!所以注解是Java程序员的必备技能,如果你对注解还不是很了解,那么我强烈建议您把这一篇文章好好读一下!

本篇文章相对来说比较长,但是很多都是代码示例,有时候光通过理论并不能很好的掌握新技能,当看完理论感觉确实掌握了,但是过一段时间就忘了,所以学习一项技能,一定是理论加实践才会更加牢固!

目录

    • 一、概念
      • 1.1. 什么是注解?
      • 1.2. 什么是元数据?
      • 1.3. 注解的属性
    • 二、根据【注解参数】 分类
      • 2.1. 标记注解
      • 2.2. 单元素注解
      • 2.3. 多元素注解
    • 三、根据【注解作用】分类
      • 3.1. 预定义的注解
        • 3.1.1. @Deprecated
        • 3.1.2. @Override
        • 3.1.3. @SuppressWarnings
        • 3.1.4. @SafeVarargs
        • 3.1.5. @FunctionalInterface
      • 3.2. 元注解
        • 3.2.1. @Retention
        • 3.2.2. @Documented
        • 3.2.3. @Target
        • 3.2.4. @Inherited
        • 3.2.5. @Repeatable
        • 3.2.6. @Native
      • 3.3. 自定义注解
    • 四、反射
      • 4.1. 反射常用到的API
      • 4.2. 读取类上的注解
      • 4.3. 读取方法上的注解
      • 4.4. 读取字段上的注解
      • 4.5. 读取方法参数注解
      • 4.6. 注解配合枚举使用

一、概念

1.1. 什么是注解?

Java注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

如果要对于元数据的作用进行分类,还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:

  • ① 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
  • ② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
  • ③ 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解单值注解完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问

首先一定要明白注解他本身是没有任何作用的,比如@RequestMapping,在controller层@RequestMapping基本上可以说是必见的,我们都知道他的作用是请求映射,通过他来设置请求的url地址,举例:将@RequestMapping("config")写在方法上,然后我们就可以通过url地址访问到这个方法了,但是记住这并不是@RequestMapping注解的功能,SpringMVC会通过反射将注解当中设置的属性值config拿到,然后将url和你声明注解的方法进行绑定。记住:注解只是用来标记,而这个注解真正的功能都是由框架通过反射来实现的

1.2. 什么是元数据?

元数据是一个非常广泛的概念,元数据的定义也非常简单,只要是描述数据的数据都是元数据。很简单,一个数字170,单看数据你肯定不知道这个数据代表什么,这就需要元数据支持,你才能明白数据代表的事实是什么。它可能是一个人的身高,也可能指一个人的体重,这需要数据对应的标题、单位等信息来描述这个数据,这些就是描述这个数据的元数据了

1.3. 注解的属性

注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    int id();
    String msg();
}

上面代码定义了 TestAnnotation 这个注解中拥有 id 和 msg 两个属性。在使用的时候,我们应该给它们进行赋值。

赋值的方式是在注解的括号内以 value=”” 形式,多个属性之前用 ,隔开。

@TestAnnotation(id=3,msg="hello annotation")
public class Test {
}

需要注意的是,在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。

注解中属性可以有默认值,默认值需要用 default 关键值指定。比如:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    public int id() default -1;
    public String msg() default "Hi";
}

TestAnnotation 中 id 属性默认值为 -1,msg 属性默认值为 Hi。

二、根据【注解参数】 分类

根据注解参数的个数,我们可以将注解分为:标记注解单值注解完整注解三类。

2.1. 标记注解

标记注解不包含成员/元素。它仅用于标记声明。

其语法为:@AnnotationName()

  • 由于这些注解不包含元素,因此不需要括号。例如:@Override

2.2. 单元素注解

单个元素注解仅包含一个元素。

其语法为:@AnnotationName(elementName = "elementValue")

  • 如果只有一个元素,则习惯上将该元素命名为value:@AnnotationName(value = "elementValue")
  • 在这种情况下,也可以移除元素名称。元素名称默认为value:@AnnotationName("elementValue")

2.3. 多元素注解

这些注解包含多个用逗号分隔的元素。

其语法为:@AnnotationName(element1 = "value1", element2 = "value2")

三、根据【注解作用】分类

3.1. 预定义的注解

这几个注解都是java.lang包下的,也就是Java提供的基础注解,我们在使用的时候是不需要导包的!

3.1.1. @Deprecated

此注解可以用在方法,属性,类上,表示不推荐程序员使用,但是还可以使用,示例如下:

在这里插入图片描述

/**
 * 测试Deprecated注解
 * @author Administrator
 */
public class DeprecatedDemoTest {
    public static void main(String[]args) {
        // 使用DeprecatedClass里声明被过时的方法
        DeprecatedClass.DeprecatedMethod();
    }
}

class DeprecatedClass {
    @Deprecated
    public static void DeprecatedMethod() {
    }
}

3.1.2. @Override

它的作用是对覆盖超类中方法的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发出错误警告。

public interface Test {
    public String getStr();
}

class TestImpl implements Test{

	// 假如返回参数和方法参数其中一个不一致,就会警告
    @Override
    public String getStr() {
        return null;
    }
}

3.1.3. @SuppressWarnings

我们在写代码的时候,不论是导入的包,还是声明的对象,有时候会出现黄线,感觉就很难受!

@SuppressWarnings注解主要用在取消一些编译器产生的警告,警告对于运行代码实际上并没有影响,但是出于部分程序员具有洁癖的嗜好,通常会采用@SuppressWarnings来消除警告。

示例一:警告如图所示

Java注解-最通俗易懂的讲解_第1张图片
这只是一个service接口:

public interface BannerService {
}

这时候我们在方法上加上@SuppressWarnings注解就可以消除这些警告的产生,注解的使用方式有三种:

  1. @SuppressWarnings(“unchecked”) [^ 抑制单类型的警告]
  2. @SuppressWarnings(“unchecked”,“rawtypes”) [^ 抑制多类型的警告]
  3. @SuppressWarnings(“all”) [^ 抑制所有类型的警告]

通过源码分析可知@SuppressWarnings其注解目标为类、字段、函数、函数入参、构造函数和函数的局部变量。建议把注解放在警告发生的位置。

消除警告:

Java注解-最通俗易懂的讲解_第2张图片

这个警告是spring framerwork 4.0以后开始出现的,spring 4.0开始就不推荐使用属性注入,改为推荐构造器注入和setter注入。当然他只是推荐,如果我们想要消除警告也可以直接使用@Resource。尽管他推荐了,但是一般实际开发当中很少会使用构造器注入和setter注入。

  1. @Autowired 是Spring提供的,@Resource 是J2EE提供的。

  2. @Autowired与@Resource都可以用来装配bean,都可以写在字段或setter方法上

  3. @Autowired默认按类型装配,默认情况下必须要求依赖对象存在,如果要允许null值,可以设置它的required属性为false。如果想使用名称装配可以结合@Qualifier注解进行使用。

  4. @Resource,默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行名称查找。如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配

示例二:警告如图所示

Java注解-最通俗易懂的讲解_第3张图片

通过添加@SuppressWarnings("unchecked")来消除unchecked的警告,这个警告实际上主要是集合没有加泛型导致的!

Java注解-最通俗易懂的讲解_第4张图片

Java注解-最通俗易懂的讲解_第5张图片

3.1.4. @SafeVarargs

在声明具有模糊类型(比如:泛型)的可变参数的构造函数或方法时,Java编译器会报unchecked警告。鉴于这些情况,如果程序员断定声明的构造函数和方法的主体不会对其varargs参数执行潜在的不安全的操作,可使用@SafeVarargs进行标记,这样的话,Java编译器就不会报unchecked警告。

使用前提:

  1. 方法必须是由static或者final修饰的方法
  2. 只能用于标记构造函数和方法
  3. 只能用在可变长参数的方法上
@SafeVarargs
public static <T> T useVarargs(T... args) {  
    return args.length > 0 ? args[0] : null;  
} 

3.1.5. @FunctionalInterface

被@FunctionalInterface注解标记的类型表明这是一个函数接口。从概念上讲,函数接口只有一个抽象方法。也就是一旦不满足函数接口,就会报错,比如他有两个抽象方法。

@FunctionalInterface注解,只能用于接口类。其实,它的应用范围更小,只能应用于接口类型。

@FunctionalInterface
public interface Test {
    public String getStr();
}

3.2. 元注解

以下的注解都来源于java.lang.annotation,描述数据的数据都是元数据,描述注解的注解都是元注解!也就是这些注解只能用在修饰注解上,不能使用在其他地方,比如方法、类等等!

@Native注解除外,他的使用范围是FIELD(字段、枚举的常量),但是@Native也是在java.lang.annotation包下!

Java注解-最通俗易懂的讲解_第6张图片

3.2.1. @Retention

注解按生命周期来划分可分为3类:

  • RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;也就是编译时有效。
  • RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;加载时被抛弃。
  • RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;一直有效!

lombok可以通过@Data注解省去get set 方法,实际上@Data的生命周期就是RetentionPolicy.SOURCE,他是通过注解来标记这个方法要生成get set方法,然后在编译的时候直接会生成get set。生成过后,就被抛弃了。

在这里插入图片描述

3.2.2. @Documented

@Documented@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成文档时,会显示@B。如果@B没有被@Documented标注,最终生成的文档中就不会显示@B。这里的生成文档指的JavaDoc文档!

@Deprecated注解基本上所有框架自定义的注解都会添加,所谓javadoc其实就是JDK给我们提供的一个生成文档的工具!

由于篇幅问题,@Documented详解请看这篇文章:https://blog.csdn.net/weixin_43888891/article/details/126981711

3.2.3. @Target

@Target:@Target只能用在注解上,指定修饰的注解的使用范围

  • @Target(ElementType.TYPE) —— 接口、类、枚举、注解
  • @Target(ElementType.FIELD) —— 字段、枚举的常量
  • @Target(ElementType.METHOD) —— 方法
  • @Target(ElementType.PARAMETER) —— 方法参数
  • @Target(ElementType.CONSTRUCTOR) —— 构造函数
  • @Target(ElementType.LOCAL_VARIABLE) —— 局部变量
  • @Target(ElementType.ANNOTATION_TYPE) —— 注解
  • @Target(ElementType.PACKAGE) —— 包

比如@Target({ElementType.TYPE, ElementType.METHOD}),就代表着@RequestMapping可以用在 接口、类、枚举、注解上、还可以用在方法上!

Java注解-最通俗易懂的讲解_第7张图片

3.2.4. @Inherited

如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解。

当用了@Inherited修饰的注解的@Retention是RetentionPolicy.RUNTIME,则增强了继承性,在反射中可以获取得到

代码示例:

1.首先自定义一个注解使用@Inherited修饰,然后这个注解用来修饰到父类上

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ATable {
    public String name() default "";
}

2.这个注解带不带@Inherited都可以,我们主要用来修饰子类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BTable {
    public String name() default "";
}

2.定义一个父类跟一个子类,然后在父类上用上我们自定义的@ATable注解

@ATable
public class Super {
    public static void main(String[] args) {
        Class<Sub> clazz = Sub.class;
        System.out.println("============================AnnotatedElement===========================");
        // 获取自身和父级带有@Inherited修饰的注解。如果@ATable未加@Inherited修饰,则获取的只是自身的注解而无法获取父级修饰的@ATable注解
        System.out.println(Arrays.toString(clazz.getAnnotations()));
        System.out.println("------------------");
    }
}
@BTable
class Sub extends Super {
}

3.这个是@ATable带有@Inherited修饰的 运行结果。

在这里插入图片描述
4.这个是没有用@Inherited修饰的 运行结果。

Java注解-最通俗易懂的讲解_第8张图片

3.2.5. @Repeatable

@Repeatable 注解是用于声明其它类型注解的元注解,来表示这个声明的注解是可重复的。@Repeatable的值是另一个注解,其可以通过这个另一个注解的值来包含这个可重复的注解

代码示例:

1.自定义Value注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {
    String value() default "value";
}

2.自定义Values 注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Values {
    Value[] value();
}

其中,@Value注解上的元注解@Repeatable中的值,使用了@Values注解,@Values注解中包含的值类型是一个@Value注解的数组!这就解释了官方文档中@Repeatable中值的使用。

3.测试

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;

public class AnnotationClass {

    @Value("hello")
    @Value("world")
    public void test(String var1, String var2) {
        System.out.println(var1 + " " + var2);
    }

    public static void main(String[] args) {
        Method[] methods = AnnotationClass.class.getMethods();
        for (Method method : methods){
            if (method.getName().equals("test")) {
                Annotation[] annotations = method.getDeclaredAnnotations();
                System.out.println(annotations.length);
                System.out.println(method.getName() + " = " + Arrays.toString(annotations));
            }
        }
    }
}

4.运行结果

在这里插入图片描述

5.假如Value注解没有使用@Repeatable修饰,编译器会报错,是不允许出现注解重复的

在这里插入图片描述
注意事项:

  1. @Repeatable 所声明的注解,其元注解@Target的使用范围要比@Repeatable的值声明的注解中的@Target的范围要大或相同,否则编译器错误,显示@Repeatable值所声明的注解的元注解@Target不是@Repeatable声明的注解的@Target的子集
  2. @Repeatable注解声明的注解的元注解@Retention的周期要比@Repeatable的值指向的注解的@Retention得周期要小或相同。

周期长度为 SOURCE(源码) < CLASS (字节码) < RUNTIME(运行)

3.2.6. @Native

@Native注解修饰成员变量,则表示这个变量可以被本地代码引用,常常被代码生成工具使用。对于 @Native 注解不常使用,了解即可!

3.3. 自定义注解

  1. 修饰符: 访问修饰符必须为public,不写默认为pubic;
  2. 关键字: 关键字为@interface;
  3. 注解名称: 注解名称为自定义注解的名称,使用时还会用到;
  4. 注解内容: 注解中内容,对注解的描述。

我们自定义一个注解,然后这个注解可以在entity当中的set方法上初始化值。只是一个简单案例,供大家参考学习!

第一步:自定义@Init注解

@Documented
@Inherited
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})  //可以在字段、枚举的常量、方法
@Retention(RetentionPolicy.RUNTIME)
public @interface Init {
    String value() default "";
}

第二步:创建User类

public class User {
    private String name;
    private String age;

    public String getName() {
        return name;
    }

    @Init("louis")
    public User setName(String name) {
        this.name = name;
        return this;
    }

    public String getAge() {
        return age;
    }

    @Init("22")
    public User setAge(String age) {
        this.age = age;
        return this;
    }
}

第三步:创建User的工厂类,所谓工厂类就是专门为了生产User对象

import java.lang.reflect.Method;

public class UserFactory {
    public static User create() {
        User user = new User();
        // 获取User类中所有的方法(getDeclaredMethods也行)
        Method[] methods = User.class.getMethods();
        try {
            for (Method method : methods) {
                // 判断方法上是否存在Init注解,存在就返回true,否则返回false
                if (method.isAnnotationPresent(Init.class)) {
                    // 此方法返回该元素的注解在此元素的指定注释类型(如果存在),否则返回null
                    Init init = method.getAnnotation(Init.class);
                    // 如果Method代表了一个方法 那么调用它的invoke就相当于执行了它代表的这个方法,在这里就是给set方法赋值
                    method.invoke(user, init.value());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return user;
    }
}

第四步:测试

public static void main(String[] args) {
    User user = UserFactory.create();
    user.setAge("30");
    System.out.println(user.getName());
    System.out.println(user.getAge());
}

第五步:运行结果,我们并没有设置User的name属性,只是在User类的 set方法 添加了一个注解。输出结果如下:

Java注解-最通俗易懂的讲解_第9张图片

四、反射

JAVA机制反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。Java注解一旦离开了反射就什么都不是!!!

4.1. 反射常用到的API

1.只能拿到public方法(包括继承的类或接口的方法)

public Method[] getMethods()

2.getDeclaredMethods返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

public Method[] getDeclaredMethods()

3.在Class对象和Method对象是都存在isAnnotationPresent这个方法的,作用是判断它是否应用了某个注解

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}

4.通过 getAnnotation() 方法来获取 Annotation 对象。

 public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

5.或者是 getAnnotations() 方法,获取所有的注解

如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了。

public Annotation[] getAnnotations() {}

6.获取到Annotation之后,就可以通过annotationType获取注解的class结构信息,有了class信息就可以获取注解的变量名,等等

Class<? extends Annotation> annotationType();

7.getParameterAnnotations :返回表示按照声明顺序对此 Method 对象所表示方法的形参进行注释的那个数组的数组

public Annotation[][] getParameterAnnotations();

4.2. 读取类上的注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    public int id() default -1;

    public String msg() default "Hi";
}
import java.lang.reflect.Method;

@TestAnnotation(id = 222,msg = "awdawd")
public class Test {
    public static void main(String[] args) {
        Method[] declaredMethods1 = TestAnnotation.class.getDeclaredMethods();
        for (Method meth : declaredMethods1) {
            System.out.println("注解的变量名为:" + meth.getName());
        }

        // 首先判断Test类上是否使用了TestAnnotation注解
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
        if (hasAnnotation) {
            // 获取注解,这个相当于是真正的拿到注解了,只有获取到这个才能获取到注解当中设置的值
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
            System.out.println("id:" + testAnnotation.id());
            System.out.println("msg:" + testAnnotation.msg());
        }
    }
}

输出结果:

Java注解-最通俗易懂的讲解_第10张图片

4.3. 读取方法上的注解

public class User {
    private String name;
    private String age;

    public String getName() {
        return name;
    }

    @Init("louis")
    public User setName(String name) {
        this.name = name;
        return this;
    }

    public String getAge() {
        return age;
    }

    @Init("22")
    public User setAge(String age) {
        this.age = age;
        return this;
    }
}
//读取注解信息
public class ReadAnnotationInfoTest {
    public static void main(String[] args) throws Exception {
        // 测试AnnotationTest类,得到此类的类对象
        Class c = Class.forName("com.gzl.cn.springbootnacos.my.User");
        // 获取该类所有声明的方法
        Method[] methods = c.getDeclaredMethods();
        // 声明注解集合
        Annotation[] annotations;
        // 遍历所有的方法得到各方法上面的注解信息
        for (Method method : methods) {
            // 获取每个方法上面所声明的所有注解信息
            annotations = method.getDeclaredAnnotations();
            System.out.println("方法名为:" + method.getName());

            if (method.isAnnotationPresent(Init.class)){
                Init annotation = method.getAnnotation(Init.class);
                System.out.println("注解设置的value值为:" + annotation.value());
            }

            for (Annotation an : annotations) {
                System.out.println("其上面的注解为:" + an.annotationType().getSimpleName());
                // 获取注解class对象
                Class<? extends Annotation> aClass = an.annotationType();
                // 通过class对象获取他的所有属性方法
                Method[] meths = aClass.getDeclaredMethods();
                // 遍历每个注解的所有变量
                for (Method meth : meths) {
                    System.out.println("注解的变量名为:" + meth.getName());
                }
            }
        }
    }
}

输出结果:

Java注解-最通俗易懂的讲解_第11张图片

4.4. 读取字段上的注解

public class User {
    @Init("张三")
    private String name;
    @Init("33")
    private String age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

public static void main(String[] args) throws IllegalAccessException {
        User user = new User();
        user.setAge("111");
        user.setName("www");

        Class<User> userClass = User.class;
        Field[] fields = userClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println("属性名称是:" + field.getName());
            Init annotation = field.getAnnotation(Init.class);
            System.out.println("注解的value值是:" + annotation.value());
            // 字段是私有的想要获取就需要将Accessible设置为true,否则报错
            field.setAccessible(true);
            Object o = field.get(user);
            System.out.println("user对象的属性值是:" + o);
            System.out.println();
        }
    }

输出的结果:

Java注解-最通俗易懂的讲解_第12张图片

4.5. 读取方法参数注解

@RequestMapping(value = "/get", method = RequestMethod.GET)
@ResponseBody
public boolean get(@RequestParam("username") String usname) {
    return useLocalCache;
}
public static void main(String[] args) throws NoSuchMethodException {
    Class<ConfigController> configControllerClass = ConfigController.class;
    // 获取get方法,第一个参数是方法名,第二个是参数类型
    Method get = configControllerClass.getDeclaredMethod("get", String.class);
    // 方法上可能有多个参数,每个参数上可能有多个注解,所以是二维数组
    // annotations[0][0]表示第1个参数的第1个注解
    // annotations[0][1]表示第1个参数的第2个注解
    Annotation[][] annotations = get.getParameterAnnotations();

    for (int i = 0; i < annotations.length; i++) {
        for (int j = 0; j < annotations[i].length; j++) {
            if (annotations[i][j] instanceof RequestParam) {
                RequestParam myParam1 = (RequestParam) annotations[i][j];
                System.out.println(myParam1.value());
            }
        }
    }
}

输出结果:

在这里插入图片描述

4.6. 注解配合枚举使用

@RequestMapping当中method属性就是使用的枚举。

@RequestMapping(value = "/get", method = RequestMethod.GET)
@ResponseBody
public boolean get(@RequestParam("username") String usname) {
    return useLocalCache;
}
public static void main(String[] args) throws NoSuchMethodException {
    Class<ConfigController> configControllerClass = ConfigController.class;
    // 获取get方法,第一个参数是方法名,第二个是参数类型
    Method get = configControllerClass.getDeclaredMethod("get", String.class);
    RequestMapping annotation = get.getAnnotation(RequestMapping.class);
    RequestMethod[] method = annotation.method();
    RequestMethod requestMethod = method[0];
    switch (requestMethod) {
        case GET:
            System.out.println("get请求");
            break;
        case POST:
            System.out.println("post请求");
            break;
    }
}

输出结果:

Java注解-最通俗易懂的讲解_第13张图片

写作不易,如果这篇文章确实帮助到您了,麻烦您给小编留个赞,谢谢!

你可能感兴趣的:(Java基础,java,spring,面试,注解)