文章

注解

注解

注解

  • 可以被其他程序(如编译器)读取

内置注解

  • @Override
  • @Deprecated
  • @SuppressWarnings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Test1 {

    // 重写的注释
    @Override
    public String toString(){
        return super.toString();
    }

    // 镇压警告
    @SuppressWarnings("all")
    public void test2(){
         List list = new ArrayList<>();
    }

    // 已经过时的,不推荐使用
    @Deprecated
    public void test(){

    }
}

元注解:注解其他的注解

  • @Target

    ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上

    ElementType.FIELD:允许作用在属性字段上

    ElementType.METHOD:允许作用在方法上

    ElementType.PARAMETER:允许作用在方法参数上

    ElementType.CONSTRUCTOR:允许作用在构造器上

    ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上

    ElementType.ANNOTATION_TYPE:允许作用在注解上

    ElementType.PACKAGE:允许作用在包上

  • @Retention

    RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件

    RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件

    RetentionPolicy.RUNTIME:永久保存,可以反射获取

  • @Document
  • @Inherited

示例

1
2
3
4
5
6
7
// 定义一个注解
@Target(value = ElementType.METHOD)         // 表示注解可以用在哪些地方
@Retention(value = RetentionPolicy.RUNTIME) // 表示注解在什么地方有效 Runtime>Class>Sources
@Documented                                 // 表示注解是否应当被包含在 JavaDoc 文档中
@Inherited                                  // 表示该类的子类将自动继承父类的该注解
@interface MyAnnotation {
}
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
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

class Test {
    // 注解可以显式赋值,如果没有,必须默认注解赋值
    @MyAnnotation2(name = "haha")
    public void test() {
    }

    @MyAnnotation3("注解只有一个时,用value或者省略value=,直接写内容")
    public void test2() {
    }
}


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2 {
    // 注解的参数,不是方法:参数类型 + 参数名()
    String name();

    int age() default 0;

    int id() default -1;// 默认值为-1,代表不存在

    String[] schools() default {"a", "b"};
}

@interface MyAnnotation3 {
    // 注解的参数,不是方法:参数类型 + 参数名()
    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
package test.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

// JsonField 注解的生命周期是 RUNTIME,也就是运行时有效。
@Retention(RetentionPolicy.RUNTIME)
// JsonField 注解装饰的目标是 FIELD,也就是针对字段的。
@Target(ElementType.FIELD)
// 创建注解需要用到@interface关键字。
@interface JsonField {
    // JsonField注解有一个参数,名字为value,类型为String,默认值为一个空字符串
    // value允许注解的使用者提供一个无需指定名字的参数
    // default允许在一个字段上直接使用@JsonField,而无需指定参数的名和值。
    public String value() default "";
}

class Writer {
    private int age;

    // name上的@JsonField注解提供了显式的字符串值。
    @JsonField("writerName")
    private String name;

    // bookName上的@JsonField注解使用了缺省项。
    @JsonField
    private String bookName;

    public Writer(int age, String name, String bookName) {
        this.age = age;
        this.name = name;
        this.bookName = bookName;
    }

    @Override
    public String toString() {
        return "Writer{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", bookName='" + bookName + '\'' +
                '}';
    }
}

class JsonSerializer {
    // 序列化对象
    public static String serialize(Object object) throws IllegalAccessException {
        Class<?> objectClass = object.getClass();
        Map<String, String> map = new HashMap<>();
        // objectClass.getDeclaredFields()通过反射的方式获取对象声明的所有字段
        for (Field field : objectClass.getDeclaredFields()) {
            // 将反射对象的可访问性设置为 true,供序列化使用
            field.setAccessible(true);
            //  判断字段是否装饰了JsonField注解
            if (field.isAnnotationPresent(JsonField.class)) {
                map.put(getSerializedKey(field), (String) field.get(object));
            }
        }
        return toJsonString(map);
    }

    private static String getSerializedKey(Field field) {
        // 获取字段上注解的值
        String annotationValue = field.getAnnotation(JsonField.class).value();
        // 如果注解的值是空的,则返回字段名
        return annotationValue.isEmpty() ? field.getName() : annotationValue;
    }

    // 借助Stream流的方式返回格式化后的JSON字符串
    private static String toJsonString(Map<String, String> jsonMap) {
        String elementsString = jsonMap.entrySet()
                .stream()
                .map(entry -> "\"" + entry.getKey() + "\":\"" + entry.getValue() + "\"")
                .collect(Collectors.joining(","));
        return "{" + elementsString + "}";
    }
}

public class Test {
    public static void main(String[] args) throws IllegalAccessException {
        Writer writer = new Writer(18, "二狗", "劲椎病康复指南");
        // {"bookName":"劲椎病康复指南","writerName":"二狗"}
        // age字段没有装饰@JsonField注解,所以没有序列化
        // name字段装饰了@JsonField注解,并且显示指定了字符串“writerName”,所以序列化后变成了 writerName。
        // bookName字段装饰了@JsonField注解,但没有显式指定值,所以序列化后仍然是 bookName。
        System.out.println(JsonSerializer.serialize(writer));
    }
}
本文由作者按照 CC BY 4.0 进行授权