自定义注解

注解定义

Annontation是Java5开始引入的新特性,称为注解。用于一些工具在编译、运行时进行解析和使用、起到说明、配置的功能。

提供了一种安全类似注释的机制,用来将任何的信息或元数据与程序元素(类、方法、成员变量等)进行关联。

为程序的元素加上更直观的说明,这些说明信息是与程序的业务逻辑无关,并且指定的工具或框架使用。

Annnontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

注解用处
  1. 生成文档
  2. 跟踪代码依赖性,实现代替配置文件功能。
  3. 在编译时进行格式检查。eg:@override在方法上,若没有覆盖超类方法,编译时就能检查出。
注解原理

注解本质上是一个继承了Annotation的接口。其具体的实现类是Java运行时生成的动态代理类。

我们通过反射获取注解时,返回的是动态代理对象$Proxy1。通过代理对象调用自定义注解的方法,最终会调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。memberValues的来源是Java常量池。

元注解

自定义注解时,需使用元注解,java.lang.annotation提供了四种元注解:

  • @Documented:是否将注解信息添加在java文档中

  • @Retention:定义该注解的生命周期

    RetentionPolicy.SOURCE:在编译阶段丢弃。

    ​ 表示注解在编译结束之后就没有任何意义,不会写入字节码eg:@Override,@SuppressWarnings。
    RetentionPolicy.CLASS:在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
    RetentionPolicy.RUNTIME:始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。自定义注解通常使用这种方式

  • @Target:表示该注解用于什么地方

    ElementType参数包括

    ElementType.CONSTRUCTOR:用于描述构造器
    ElementType.FIELD:成员变量、对象、属性(包括enum实例)ElementType.LOCAL_VARIABLE:用于描述局部变量
    ElementType.METHOD:用于描述方法
    ElementType.PACKAGE:用于描述包

    ElementType.PARAMETER:用于描述参数
    ElementType.TYPE:用于描述类、接口(包括注解类型)或enum声明

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

常见标准注解
  1. @Override
    java.lang.Override是一个标记类型注解,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时, java编译器将以一个编译错误来警示。
  2. @Deprecated
    Deprecated也是一种标记类型注解。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。所以使用这种修饰具有一定的“延续性”︰如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。
  3. @ SuppressWarnings
    SuppressWarning不是一个标记类型注解。它有一个类型为String]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。
    @SuppressWarnings( "unchecked”)
自定义注解
  1. 所有的注解自动继承Java.lang.Annotation接口,并且不能继承别的类或是接口。
  2. 参数成员只能用public或default这两个访问修饰符
  3. 参数成员只能用八种基本数据类型以及String、Enum、Class、annotations及这些类型的数组
  4. 要获取类方法和字段的注解信息,必须通过Java的反射来获取Annotation对象,没有其他获取注解对象的方法
  5. 注解可以没有自定义成员,不过这样的注解没意义。
实例
实体
public class Apple {
    @FruitName("苹果")
    private String name;
    @FruitColor(fruitColor=FruitColor.Color.GREEN)
    private String color;
    @FruitProvide(id=666,name="山西供应商",address = "山西省运城市")
    private String privide;

//省略get,set方法
}
注解处理类

可加自己逻辑

public class FruitInfoUtils {
    public static void getFruitInfo(Class<?> clazz){
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(FruitName.class)){
                FruitName fruitName = field.getAnnotation(FruitName.class);
                System.out.println("水果名===》》》"+fruitName.value());
            }else if(field.isAnnotationPresent(FruitColor.class)){
                FruitColor annotation = field.getAnnotation(FruitColor.class);
                System.out.println("水果颜色===》》》"+annotation.fruitColor());
            }else if(field.isAnnotationPresent(FruitProvide.class)){
                FruitProvide annotation = field.getAnnotation(FruitProvide.class);
                System.out.println("水果供应商===》》》"+annotation.id()+" "+annotation.name()+" "+annotation.address());
            }
        }
    }
    public static void main(String[] args) {
        getFruitInfo(Apple.class);
    }
}

在这里插入图片描述

自定义注解
//@FruitName注解定义
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}
//@FruitColor注解定义
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {

    public enum Color{RED,GREEN,YELLOW};

    Color fruitColor() default Color.RED;
}
//@FruitProvide注解定义
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvide {
    /**
     * 供应商id
     */
    public int id() default -1;
    /**
     * 供应商名称
     */
    public String name() default "";
    /**
     * 供应商地址
     */
    public String address() default "";
}
自定义注解一般使用场景

自定义注解+拦截器,可实现登录校验

自定义注解+AOP

参考百度文库—

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值