自定义Java注解

注解的作用:

1.生成文档
这是最常见的,也是java 最早提供的注解。常用的有 @see @param @return 等

2.跟踪代码依赖性,实现替代配置文件功能
Spring中大量运用注解来简化配置文件

3.在编译时进行格式检查

如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出

实现一个简单的注解:

@Retention(RetentionPolicy.RUNTIME)
public @interface MyTarget {
}
上面是一个最简单的注解实现,没有定义任何的属性
需要注意的是@Retention(RetentionPolicy.RUNTIME)是定义注解所必须的。
 
@Retention是注解的注解,称为注解的元注解。
括号里有一个枚举类型的值,即为注解内部定义的值。打开Retention的实现:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}
可以看到这里定义了一个变量value并且没有缺省值,所以不写这个value就会报错。 
继续打开RetentionPolicy:
public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}
可以发现这个枚举类定义了三个值,这三个值分别代表的是我们定义的MyTarget如何保持。

@Retention(RetentionPolicy.CLASS)
注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候

@Retention(RetentionPolicy.SOURCE)
注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中

@Retention(RetentionPolicy.RUNTIME)
注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时

还需要注意的是java的元注解一共有四个: 
@Document 
@Target 
@Retention 
@Inherited

各个的作用,读者自己查一下吧。

注解处理的一个基础:
 T getAnnotation(Class annotationClass): 
返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。

Annotation[] getAnnotations():
返回该程序元素上存在的所有注解。

boolean is AnnotationPresent(Class annotationClass):
判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.

Annotation[] getDeclaredAnnotations():
返回直接存在于此元素上的所有注释。
与此接口中的其他方法不同,该方法将忽略继承的注释。
(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)
该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

实现为属性赋值的注解:
package com.justin.test.util;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface CarNameTarget {
    String name() default "";
}
package com.justin.test.util;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface CarSalerTarget {
    String salerName();

    int age() default 1;
}
package com.justin.test.entity;

import com.justin.test.util.CarNameTarget;
import com.justin.test.util.CarSalerTarget;

/**
 * 描述:
 * 汽车实体类
 *
 * @author 孫兵
 * @create 2018-05-15 10:16
 */
public class BnechCar {
    @CarNameTarget(name = "奔驰")
    private String name;

    @CarSalerTarget(salerName = "justin", age = 22)
    private String salerInfo;
}
package com.justin.test.util;

import java.lang.reflect.Field;

/**
 * 描述:
 * 汽车信息工具类
 *
 * @author 孫兵
 * @create 2018-05-15 10:19
 */
public class CarInfoUtil {

    public static void getFruitInfo(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(CarNameTarget.class)) {
                CarNameTarget carNameTarget = field.getAnnotation(CarNameTarget.class);
                String carColour = "汽车的中文名:" + carNameTarget.name();
                System.out.println(carColour);
            } else if (field.isAnnotationPresent(CarSalerTarget.class)) {
                CarSalerTarget carSalerTarget = field.getAnnotation(CarSalerTarget.class);
                String salerInfo = "销售员姓名:" + carSalerTarget.salerName() + ",年龄:" + carSalerTarget.age();
                System.out.println(salerInfo);
            }
        }
    }
}
/**
     * 自定义注解测试
     */
    private void targetTest() {
        CarInfoUtil.getFruitInfo(BnechCar.class);
    }

打印信息:

汽车的中文名:奔驰
销售员姓名:justin,年龄:22