• 枚举-注解原理总结 (1)


    注解概念:
    Java 注解(Annotation),是 JDK5.0 引入的一种注释机制。Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。注解可以被看作是对一个类/方法的一个扩展的模版,按照注解类中的规则,处理不同的逻辑。
    注解的作用:

    • 编写文档:通过代码里标识的注解生成文档
    • 编译检查:通过代码里标识的注解让编译器实现基本的编译检查
    • 代码分析:通过代码里标识的注解对代码进行分析

    Java 注解使本来可能需要很多配置文件,需要很多逻辑才能实现的内容,可以使用一个或者多个注解来替代,这样就使得编程更加简洁,代码更加清晰。Java 注解在框架代码如Spring boot中得到了广泛的应用。
    最常用的3种注释为:

    • @Override - 编译检查,告诉编译器这个是个覆盖父类的方法。如果父类删除了该方法,则子类会报错。
    • @Deprecated - 编译检查,表示被注解的元素已被弃用。
    • @SuppressWarnings - 编译检查,告诉编译器忽略警告。

    元注解
    有童鞋会问,Deprecated是注解,怎么它的上方还有注解?@Retention,@Target是什么鬼?@Retention,@Target都被称为元注解,元注解顾名思义我们可以理解为注解的注解,它是作用在注解中,方便我们使用注解实现想要的功能。元注解分别有@Retention、 @Target、 @Document、 @Inherited和@Repeatable(JDK1.8加入)五种。
    @Retention

    • @Retention表示注解存在的生命周期,是保留在源码(编译期)时期,还是字节码(类加载)或者运行期(JVM中运行)时期。在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期
    • @Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含
    • @Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
    • @Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到
    • 自定义注解必须选择@Retention(RetentionPolicy.RUNTIME)

    @Target

    • @Target元注解表示我们的注解作用的范围,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型
    • @Target(ElementType.TYPE) 作用接口、类、枚举、注解
    • @Target(ElementType.FIELD) 作用属性字段、枚举的常量
    • @Target(ElementType.METHOD) 作用方法
    • @Target(ElementType.PARAMETER) 作用方法参数
    • @Target(ElementType.CONSTRUCTOR) 作用构造函数
    • @Target(ElementType.LOCAL_VARIABLE)作用局部变量
    • @Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
    • @Target(ElementType.PACKAGE) 作用于包
    • @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
    • @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)

    @Documented

    • Document的意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。

    @Inherited

    • Inherited的意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。

    @Repeatable

    • Repeatable的英文意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义。

    注解属性
    注解只有成员变量,没有方法。以下我们定义了一个方法注解,作用在方法上,有name和age两种属性。

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyAnnotation {
        String name() default "sheldon";
        int age();
    }

    对注解中的属性赋值,因为name已经赋予了默认值sheldon,因此只需再给age赋值即可,如下。 

    public class Student {
        @MyAnnotation(age = 26)
        public void test() {
        }
    }

    获取注解属性
    获取注解属性是使用注解的关键,获取注解属性的方法都是基于反射

    public class AnnotationTest {
        public static void main(String[] args) throws Exception {
            Class<?> studentClass = Student.class;
            Method method = studentClass.getMethod("test");
            //判断test()方法上是否存在@MyAnnotation注解
            boolean isPresent = method.isAnnotationPresent(MyAnnotation.class);
            if (isPresent) {
                //如果存在,打印出注解中的属性值
                MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
                System.out.println(annotation.name());
                System.out.println(annotation.age());
            }
        }
    }

    输出

    sheldon
    26

    应用 - 进行逻辑判断
    既然能够获取到注解的属性值,那我们便可以进行逻辑判断。下面我们看一个银行转账的例子,假设银行有个转账业务,转账的限额可能会根据汇率的变化而变化,我们可以利用注解灵活配置转账的限额,而不用每次都去修改我们的业务代码。

    /**定义限额注解*/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface BankTransferMoney {
        double maxMoney() default 10000;
    }
    /**转账处理业务类*/
    public class BankService {
        /**
         * @param money 转账金额
         */
        @BankTransferMoney(maxMoney = 15000)
        public static void TransferMoney(double money){
            System.out.println(processAnnotationMoney(money));
        }
    private static String processAnnotationMoney(double money) { try { Method transferMoney = BankService.class.getDeclaredMethod("TransferMoney",double.class); boolean annotationPresent = transferMoney.isAnnotationPresent(BankTransferMoney.class); if(annotationPresent){ BankTransferMoney annotation = transferMoney.getAnnotation(BankTransferMoney.class); double maxMoney = annotation.maxMoney(); if(money > maxMoney){ return "转账金额大于限额,转账失败"; }else { return"转账金额为:"+money+",转账成功"; } } } catch ( NoSuchMethodException e) { e.printStackTrace(); } return "转账处理失败"; }
    public static void main(String[] args){ TransferMoney(10000); } }

    输出

    转账金额为: 10000.0,转账成功

    郭慕荣博客园
  • 相关阅读:
    每天一篇文献:A SURVEY OF LEARNING FROM DEMONSTRATION USED IN ROBOTICS
    PyBullet(七)在PyBullet中使用VR
    期刊模板搜索网址
    论文阅读:Robot Program Parameter Inference via Differentiable Shadow Program Inversion
    visio画图如何插入到latex中
    win10下TensorFlow-GPU安装(GTX1660+CUDA10+CUDNN7.4)
    Object detection with localization using Unity Barracuda and ARFoundation
    论文阅读:Design and Implementation of a Virtual Reality Application for Mechanical Assembly Training
    Qt开发经验小技巧151-155
    Qt开发经验小技巧146-150
  • 原文地址:https://www.cnblogs.com/jelly12345/p/15054595.html
Copyright © 2020-2023  润新知