JavaSE进阶-注解:元注解@Target

5/14/2019 注解

# JavaSE进阶-注解:元注解@Target

# 注解中的@Target

@Target的可能取值为以下枚举类中值的组合,指征当前的注解类可以在哪些位置使用

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 默认值

当一个注解没有指定@Target时,默认可以在除了TYPE_PARAMETER以外的任何上下文使用

# 分类

从类型上区分,上面10个枚举值可以分为两种,前八种出现在声明上下文中,后两种出现在类型上下文中

# 声明上下文注解

  1. 声明上下文注解包括八种,从外到内分别是包声明,类声明,Field声明,构造器声明,方法声明,参数声明,注解声明,本地变量声明
  2. 类声明,Field声明,构造器声明,方法声明,参数声明比较常用,注解的值的获取都是通过Class对象的反射来获取,需要特别注意的是,当一个变量是私有变量时,通过Field反射获取前需要setAccesible(true)
  3. 包注解,通过package-info.java类定义,通过Package类反射获取值
  Package pkg = Package.getPackage("taste.annotaions.targetdemo");
        System.out.println("PACKAGE:" + pkg.getAnnotation(PackageAnnotation.class).value());
1
2
  1. 声明类注解的使用如下代码所示
/**
 * @Author: kkyeer
 * @Description: 注解不同Target的使用与值的获取
 * @Date:Created in 22:07 2019/3/21
 * @Modified By:
 */

// 类注解
@VariousTarget.TypeAnnotation("This is before class declaration")
public class VariousTarget {
    // 构造器注解,内部是注解的注解
    @ConstructorAnnotation(value="This is a constructor annotation",ref=@AnnotationTypeAnnotation("This is a annotation of a annotation"))
    public VariousTarget(){}

    // 成员变量注解
    @FieldAnnotation("This is a field annotation")
    private String prop;

    // 方法注解,参数列表中是参数注解
    @MethodAnnotation("This is a method annotation")
    private void printSomething(@ParameterAnnotation("parameter annotation") String content) {
        // 本地变量注解,仅在源码中有效,不会被编译到class文件中
        @LocalVariableAnnotation("This ia a local variable annotation")
        String prefix = "-------";
    }


    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
        Class<VariousTarget> clazz = VariousTarget.class;
        System.out.println("TYPE:" + clazz.getAnnotation(TypeAnnotation.class).value());

        Constructor<VariousTarget> constructor = clazz.getConstructor();
        ConstructorAnnotation constructorAnnotation = constructor.getAnnotation(ConstructorAnnotation.class);
        System.out.println("CONSTRUCTOR:" + constructorAnnotation.value());
        System.out.println("ANNOTATION TYPE:"+constructorAnnotation.ref().value());
        Field field = clazz.getDeclaredField("prop");
        // 此处需要更改访问权限来获取注解值
        field.setAccessible(true);
        System.out.println("FIELD:" + field.getAnnotation(FieldAnnotation.class).value());

        Method method = clazz.getDeclaredMethod("printSomething", String.class);
        System.out.println("METHOD:" + method.getAnnotation(MethodAnnotation.class).value());
        Annotation[][] parameterAnnos = method.getParameterAnnotations();
        System.out.println("PARAMETER:" + ((ParameterAnnotation) parameterAnnos[0][0]).value());

        Package pkg = Package.getPackage("taste.annotaions.targetdemo");
        System.out.println("PACKAGE:" + pkg.getAnnotation(PackageAnnotation.class).value());
    }

    /**
     * Target为TYPE的注解
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TypeAnnotation {
        String value();
    }

    /**
     * Target为Constructor的注解
     */
    @Target(ElementType.CONSTRUCTOR)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface  ConstructorAnnotation{
        String value();
        AnnotationTypeAnnotation ref();
    }

    /**
     * Target为Field的注解
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface  FieldAnnotation{
        String value();
    }

    /**
     * Target为Method的注解
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface  MethodAnnotation{
        String value();
    }

    /**
     * Target为Parameter的注解
     */
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface  ParameterAnnotation{
        String value();
    }

    /**
     * Target为AnnotationType的注解,也就是给注解作注解的注解
     */
    @Target(ElementType.ANNOTATION_TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface  AnnotationTypeAnnotation{
        String value();
    }

    /**
     * Target为Parameter的注解
     */
    @Target(ElementType.LOCAL_VARIABLE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface  LocalVariableAnnotation{
        String value();
    }


    /**
     * Target为Parameter的注解
     */
    @Target(ElementType.PACKAGE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface  PackageAnnotation{
        String value();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

# 类型上下文注解

# 注解定义

@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeUseAnnotation {
    String value();
}
1
2
3
4
5

当一个注解的Target被指定为TYPE_USE时,这个注解的使用位置为类型参数的位置,具体参考JLS4.11,基本上可以理解为,几乎所有类型定义的位置都可以使用,试举几例如下

# 注解返回值和异常

 public @TypeUseAnnotation("Return type") String trapOperation(List<String> param) throws @TypeUseAnnotation("Exception annotation") Exception{
        if (param != null) {
            throw new Exception("You are trapped");
        }

        return null;
}
1
2
3
4
5
6
7

获取上述注解的值

Method method = clazz.getMethod("trapOperation", List.class);
// 异常列表中的注解
System.out.println(method.getAnnotatedExceptionTypes()[0].getAnnotation(TypeUseAnnotation.class).value());

// 返回值中的注解        System.out.println(method.getAnnotatedReturnType().getAnnotation(TypeUseAnnotation.class).value());
1
2
3
4
5
Last Updated: 1/22/2024, 8:56:53 AM