Java注解

98 阅读4分钟

1. 什么是注解

我们在使用Spring框架、Junit或者TestNG框架的时候,经常看到注解,有方法上注解,也有类上的注解,比如:@Autowired、@Controller、@Test等。

为什么需要加这些注解?『注解』和『XML』两种不同的配置模式,争论了好多年了,各有各的优劣,注解可以提供更大的便捷性,易于维护修改,但耦合度高,而 XML 相对于注解则是相反的。

这些注解又是如何发挥作用的?下面我们一一道来。

2.注解的使用

2.1注解的定义

下面的代码就创建了一个名为Check的注解:

package com.test.annotation;

public @interface Check {
}

我们就可以在类定义的地方使用@Check对这个类进行注解了,不过现在这个注解还不能正常工作,我们还需要用到元注解。

2.2 元注解

元注解就是作用到注解上的注解

常用的元注解有5种:

2.2.1 @Retention

当@Retention作用到一个注解上的时候,说明了一个注解的存活时间。 取值的枚举:

枚举值含义
RetentionPolicy.SOURCE注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视
RetentionPolicy.CLASS注解只被保留到编译进行的时候,它并不会被加载到 JVM 中
RetentionPolicy.RUNTIME注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们
package com.test.annotation;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}

2.2.2 @Documented

这个元注解与文档有关,它的作用是能够将注解中的元素包含到 Javadoc 中去。

2.2.3 @Target

当@Target注解作用到一个注解上的时候,他限制了这个注解的运用的地方,比如只能作用于类上或者方法上或者局部变量等。

枚举值含义
ElementType.ANNOTATION_TYPE可以给一个注解进行注解
ElementType.CONSTRUCTOR可以给构造方法进行注解
ElementType.FIELD可以给属性进行注解
ElementType.LOCAL_VARIABLE可以给局部变量进行注解
ElementType.METHOD可以给方法进行注解
ElementType.PACKAGE可以给一个包进行注解
ElementType.PARAMETER可以给一个方法内的参数进行注解
ElementType.TYPE可以给一个类型进行注解,比如类、接口、枚举

2.2.4 @Inherited

一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解作用的话,那么这个子类就继承了超类的注解。

2.2.5 @Repeatable

可多次使用的注解

@interface Persons {
	Person[]  value();
}

@Repeatable(Persons.class)
@interface Person{
	String role default "";
}

@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
	
}

注意上面的代码,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。

什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。

2.3 注解的提取

注解通过反射获取。

package com.service;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

@TestAnnotation(msg="hello")
public class Test {
    @CheckQA(value="hi")
    int a;

    @Perform
    public void testMethod(){
        System.out.println("hello, testMethod");
    }


    public static void main(String[] args) {
        Test test = new Test();

        // 获取类上的注解
        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());
        }


        try {
            //获取一个成员变量上的注解
            Field a = Test.class.getDeclaredField("a");
            a.setAccessible(true);

            CheckQA check = a.getAnnotation(CheckQA.class);
            if ( check != null ) {
                System.out.println("check value:"+check.value());
            }

            // 获取方法中的注解
            Method[] methods = Test.class.getDeclaredMethods();
            for(Method m : methods){
                System.out.println(m.getName());
                if(m.isAnnotationPresent(Perform.class)){
                    m.getAnnotation(Perform.class).annotationType().getSimpleName();
                    m.setAccessible(true);
                    m.invoke(test, null);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }

}

2.4 注解的属性

注解的属性就是注解的成员变量。

注解只有成员变量没有方法。

2.4.1 注解中属性的声明方法

package com.service;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface CheckQA {
    public String value() default "hello";
}

注解中成员变量的声明:作用范围 返回值类型 成员变量名称()

返回值类型:8 种基本数据类型外加 类、接口、注解及它们的数组

成员变量可以设置默认值:如 default "hello"

2.4.2 注解中属性的赋值

@TestAnnotation(msg="hello")
public class Test {
    @CheckQA(value="hi")
    int a;

    @Perform
    public void testMethod(){
        System.out.println("hello, testMethod");
    }
}

注解中属性的赋值方法:注解的成员变量名称=值,多个成员变量之间用逗号隔开

如果注解中只有一个成员变量,那么赋值的时候可以直接写到括号内

如果一个注解没有成员变量或者成员变量已经都设置了默认值,那么可以不用写括号

3.参考

blog.csdn.net/briblue/art…

juejin.cn/post/684490…