自定义系列 之 自定义注解

一.注解基础回顾

@interface,使用这个关键字可以说明这是一个注解。

java.lang.annotation 提供了四种元注解,可以用来注解其他的注解,像Override这些注解都会用到它们,我们自定义注解的时候也会用到,四种注解如下:

@Target:说明注解用于什么地方。

@Retention:什么时候使用注解。

@Inherited:是否允许子类继承该注解

@Documented:注解是否将包含在JavaDoc中

1,@Target的参数可以是

ElementType.TYPE : 类、接口或枚举声明

ElementType.FIELD : 字段声明(包括枚举常量)

ElementType.METHOD : 方法声明

ElementType.PACKAGE : 包声明

ElementType.CONSTRUCTOR : 构造器声明

ElementType.ANNOTATION_TYPE : 注释类型声明,解释一下,例如Target本身就是一个注解,那么他自己的target就是ANNOTATION_TYPE,即target的target是ANNOTATION_TYPE。

这些参数类型也就是类类型可以获取的类型(别扭)。

2,@Retention定义注解的生命周期,可用参数为枚举类RetentionPolicy中的类型

RetentionPolicy.SOURC : 编译器会放弃注解, 也就是编译期一过,这些注解就没有作用了。

    可以看到下面这些注解使用了SOURC ,从这些注解可以看出来,确实过了编译期就没什么用了,所以一般都是提示或校验会用到。

RetentionPolicy.CLASS : 注释将被编译器记录在类文件中,但是在运行时不需要被VM保留。这是默认行为。很少用到。

RetentionPolicy.RUNTIME : 注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以反射性地读取它们,我们自定义的注解一般都需要用到他们。

二.注解的自定义及使用过程

我们先定义两个注解,分别是ElementType.METHOD和ElementType.FIELD类型

/**
 * @author uiao
 * @Title: 自定义方法类型的注解
 * @date 2018/8/315:36
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface City {
    //默认值,如果你在方法使用了默认值,但是没有填写内容就会给附上这个值
    String code() default "010";

    String name() default "北京";
}
/**
 * @author uiao
 * @Title: 自定义属性类型的注解
 * @date 2018/8/316:11
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Phone {
    String value() default "13261201263";
}

之后我们在Company这个类上使用我们自定义的Phone和City注解

/**
 * @author uiao
 * @Title: 注解的使用
 * @date 2018/8/315:46
 */
public class Company {

    @Phone(value = "12345")
    private String phone;

    private String cityName;

    private String cityCode;

    public Company(){}

    public Company(String phone, String cityName, String cityCode) {
        this.phone = phone;
        this.cityName = cityName;
        this.cityCode = cityCode;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    @City(name = "上海", code = "020")
    public String getCityCode() {
        return cityCode;
    }

    public void setCityCode(String cityCode) {
        this.cityCode = cityCode;
    }

    @Override
    public String toString() {
        return "Company{" +
                "phone='" + phone + '\'' +
                ", cityName='" + cityName + '\'' +
                ", cityCode='" + cityCode + '\'' +
                '}';
    }
}

测试使用注解

/**
 * @author uiao
 * @Title: 自定义注解测试
 * @date 2018/8/315:39
 */
public class AnnotationTest {
    private static Logger logger = Logger.getLogger(AnnotationTest.class);

    public static void main(String[] args) {
        Company company = injectAnnotationValue(Company.class);
        // 打印输入注解后的值
        System.out.println("打印注入注解后的值 ==>>");
        System.out.println(company.toString());
    }

    public static Company injectAnnotationValue(Class<?> clazz) {
        Company company = new Company();
        // 遍历Class里使用的FIELD类型的注解

        for (Field field : clazz.getDeclaredFields()) {
            Phone phone = field.getAnnotation(Phone.class);
            if (phone != null) {
                System.out.println(clazz.getName() + "上使用了属性注解:" + field.getName() + ",注解的值为: " + phone.value());
                // 给company实例赋上注解的值
                company.setPhone(phone.value());
            }
        }
        // 遍历Class里使用的METHOD类型的注解
        for (Method method : clazz.getDeclaredMethods()) {
            City city = method.getAnnotation(City.class);
            if (city != null) {
                System.out.println(clazz.getName() + "上使用了方法注解:" + method.getName() + ",注解的值为: "
                        + " code: " + city.code()
                        + ", name: " + city.name());
                // 给company实例赋上注解的值
                company.setCityCode(city.code());
                company.setCityName(city.name());
            }
        }
        return company;
    }
}

打印结果

D:\Java\jdk1.8.0_111\bin\java ...
annotation.Company上使用了属性注解:phone,注解的值为: 12345
annotation.Company上使用了方法注解:getCityCode,注解的值为:  code: 020, name: 上海
打印注入注解后的值 ==>>
Company{phone='12345', cityName='上海', cityCode='020'}

  打印结果中可以看到我们将对象company的phone,cityCode,cityName的值都设置成了注解里的内容。

  注意:注解类型必须要用在该用的地方,就是你自定义的注解类型是method,你就不可以在field上使用它,但是。。。我们最后是通过反射来做一些操作的,所以即使你只是在一个field上使用了一个注解,但是在使用反射获取到注解后,可以随意更改对象的所有field。

  说白了注解只是给我们的类,属性或方法加打了个标签,java支持通过反射机制获取这个标签。至于获取了标签后我们可以做什么事情,就是自己说了算了,这也是多数框架只是改个注解就会起到很大作用的原因。

呃。。。下一篇会写通过实现HandlerMethodArgumentResolver接口,重写resolveArgument方法实现自定义参数注解。

猜你喜欢

转载自blog.csdn.net/fanxing1964/article/details/81479357
今日推荐