Java 注解(Annotations) 详解

注解是元数据

注解是一种装饰器、一个标记 (maker),应用于 Java 的各种结构之上,例如类、方法、字段。用来为这些结构绑定元数据。注解不包含任何业务逻辑
只由运行时框架或编译器根据注解信息去执行具体行为。

Retention and Target

保留(Retention )策略指定就程序生命周期而言,注释应该保留多长时间(一个)
目标(Target)指定注解可以应用于哪些 Java 结构 (多个)

自定义 annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonField {
    public String value() default "";
}
public class Car {
    @JsonField("manufacturer")
    private final String make;
    @JsonField
    private final String model;
    private final String year;
<span class="hljs-keyword">public</span> Car(String make, String model, String year) {
    <span class="hljs-keyword">this</span>.make = make;
    <span class="hljs-keyword">this</span>.model = model;
    <span class="hljs-keyword">this</span>.year = year;
}

## <span class="hljs-keyword">get</span> and <span class="hljs-keyword">set</span> method

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String toString() {
    <span class="hljs-keyword">return</span> year + <span class="hljs-string">" "</span> + make + <span class="hljs-string">" "</span> + model;
}

}

利用反射机制执行具体行为

public class JsonSerializer {
<span class="hljs-keyword">public</span> <span class="hljs-title class_">String</span> <span class="hljs-title function_">serialize</span>(<span class="hljs-title class_">Object</span> <span class="hljs-built_in">object</span>) throws <span class="hljs-title class_">JsonSerializeException</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-title class_">Class</span>&lt;?&gt; objectClass = requireNonNull(<span class="hljs-built_in">object</span>).<span class="hljs-title function_">getClass</span>();
        <span class="hljs-title class_">Map</span>&lt;<span class="hljs-title class_">String</span>, <span class="hljs-title class_">String</span>&gt; jsonElements = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;();

        <span class="hljs-keyword">for</span> (<span class="hljs-title class_">Field</span> <span class="hljs-attr">field</span>: objectClass.<span class="hljs-title function_">getDeclaredFields</span>()) {
            field.<span class="hljs-title function_">setAccessible</span>(<span class="hljs-literal">true</span>);
            <span class="hljs-keyword">if</span> (field.<span class="hljs-title function_">isAnnotationPresent</span>(<span class="hljs-title class_">JsonField</span>.<span class="hljs-property">class</span>)) {
                jsonElements.<span class="hljs-title function_">put</span>(<span class="hljs-title function_">getSerializedKey</span>(field), (<span class="hljs-title class_">String</span>)field.<span class="hljs-title function_">get</span>(<span class="hljs-built_in">object</span>));
            }
        }

        <span class="hljs-title class_">System</span>.<span class="hljs-property">out</span>.<span class="hljs-title function_">println</span>(<span class="hljs-title function_">toJsonString</span>(jsonElements));
        <span class="hljs-keyword">return</span> <span class="hljs-title function_">toJsonString</span>(jsonElements);

    } <span class="hljs-keyword">catch</span> (<span class="hljs-title class_">IllegalAccessException</span> e) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">JsonSerializeException</span>(e.<span class="hljs-title function_">getMessage</span>());
    }
}

<span class="hljs-keyword">private</span> <span class="hljs-title class_">String</span> <span class="hljs-title function_">toJsonString</span>(<span class="hljs-params"><span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; jsonMap</span>) {
    <span class="hljs-title class_">String</span> elementsString = jsonMap.<span class="hljs-title function_">entrySet</span>()
            .<span class="hljs-title function_">stream</span>()
            .<span class="hljs-title function_">map</span>(entry -&gt; <span class="hljs-string">"\""</span>  + entry.<span class="hljs-title function_">getKey</span>() + <span class="hljs-string">"\":\""</span> + entry.<span class="hljs-title function_">getValue</span>() + <span class="hljs-string">"\""</span>)
            .<span class="hljs-title function_">collect</span>(<span class="hljs-title class_">Collectors</span>.<span class="hljs-title function_">joining</span>(<span class="hljs-string">","</span>));
    <span class="hljs-keyword">return</span> <span class="hljs-string">"{"</span> + elementsString + <span class="hljs-string">"}"</span>;
}

<span class="hljs-keyword">private</span> <span class="hljs-title class_">String</span> <span class="hljs-title function_">getSerializedKey</span>(<span class="hljs-params">Field field</span>) {
    <span class="hljs-title class_">String</span> annotationValue = field.<span class="hljs-title function_">getAnnotation</span>(<span class="hljs-title class_">JsonField</span>.<span class="hljs-property">class</span>).<span class="hljs-title function_">value</span>();

    <span class="hljs-keyword">if</span> (annotationValue.<span class="hljs-title function_">isEmpty</span>()) {
        <span class="hljs-keyword">return</span>  field.<span class="hljs-title function_">getName</span>();
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> annotationValue;
    }
}

}

Car car = new Car("Ford", "F150", "2018");
JsonSerializer serializer = new JsonSerializer();
serializer.serialize(car);

# output
# {"model":"F150","manufacturer":"Ford"}

总结

虽然注解不应该用来代替接口或其他以面向对象的方式正确完成任务的语言结构,但它们可以极大地简化重复的逻辑。
利用注解,可以以声明式的编程方式,将与具体业务领域无关的功能(安全、事务、日志)等抽离出来。实现不同逻辑的解耦。