• 【注解学习】基础掌握与简单示例使用


    背景

    记录学习!

    • 适合未了解过注解的同学
    • 适合有注解使用经历,想巩固加深理解知识点的同学

    基础掌握

    什么是注解

    • 定义注解使用的关键字是 @interface
    • 注解是元数据的一种形式,源码中就很常见注解,故注解可以添加到代码中。比如说一个类、方法、参数、变量和包都可以添加注解。
    • 注解对它们注解的代码的操作没有直接影响。
    • 注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记。(也就是说:javac 编译器、开发工具和其他程序可以通过反射来了解你的类及各种元素上有无何种标记,看你的程序有什么标记,就去干相应的事

    元注解

    元注解就是用来定义注解的注解.其作用就是定义注解的作用范围, 使用在什么元素上等。

    元注解有4种 :

    • @Retention
      保留的范围(即Annotation被保留的时间)。默认值 CLASS
      SOURCE:只在源码中可用
      CLASS:在源码和字节码中可用
      RUNTIME:在源码、字节码和运行时均可用

    • @Target
      用来修饰哪些程序元素。例如:TYPEMETHODFIELD等。
      未标注则表示可以修饰所有

    • @Inherited
      是否可以被继承,默认是 false

    • @Documented
      是否会保存到 javadoc 文档中

    Android 开发中,Activity 中生命周期方法会用到 Override 注解,我们看下该注解的定义。该注解源码如下:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    
    • 1
    • 2
    • 3
    • 4

    这里可以看到,Override 注解是作用于方法,并在源码中使用的。


    自定义注解示例

    自定义 MyAnnotation 注解

    代码如下:

    /**
     *  自定义 MyAnnotation 注解
     *  该注解作用于方法
     *  该注解在代码运行时可用
     */
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
    
        // 属性定义 并指定了缺省值(注解的属性定义方式和接口中定义方法的方式一样)
        String hello() default "hello, world!";
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    其中 @Target(ElementType.METHOD) 表示该注解作用在方法上。

    @Retention(RetentionPolicy.RUNTIME) 表示该注解在运行时可用。

    • hello 是该注解的属性。给注解添加属性的语法如下:
    类型 属性名() default 默认值;
    
    • 1

    这是最简单的一个属性语法,还有其他一些更高级的语法同学们可以自行学习,这里不再细说。


    使用 MyAnnotation 注解

    自定义一个 Hello 类,新增一个 sayHello() 方法,在该方法上使用注解。代码如下:

    public class Hello {
    
        public Hello() {
        }
    
        // 使用 MyAnnotation 注解,给 hello 属性赋新值:"hi, imxiaoqi"
        @MyAnnotation(hello = "hi, imxiaoqi")
        public void sayHello(){
            System.out.println(":> Hello call method: sayHello()");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    由上可知,在 sayHello() 方法上使用注解,并给 hello 属性赋新值。


    解析 MyAnnotation 注解

    Retention 的值为 RUNTIME ,故注解会保留到程序运行时, 因此我们可以使用反射来解析注解。解析代码如下:

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            reflect();
    
        }
    
    	// 通过反射解析注解
        private void reflect() {
            
            try {
                Class<?> helloClass = Class.forName("com.example.annotationdemo.Hello");
                Method method = helloClass.getDeclaredMethod("sayHello", new Class[]{});
                if (method.isAnnotationPresent(MyAnnotation.class)){
                    // 方法存在注解,则获取注解
                    MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
                    //  调用注解内容
                    System.out.println(":> MyAnnotation content: " + annotation.hello());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    上面通过反射来解析 Hello 类中 sayHello() 方法上的 MyAnnotation 注解,拿到注解的 hello 属性内容。代码相对来说简单!


    解析结果验证

    我们将这个程序运行在虚拟机上,然后通过 logcat 日志打印输出来验证我们注解解析的一个结果。

    安装运行后,logcat 输出打印内容如下:

    在这里插入图片描述
    这里成功获取到了注解的属性值。


    总结

    定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应的注解信息处理流程,注解可以说是没有实用价值。如何让注解真真的发挥作用,主要就在于注解处理方法,多实践使用,具体情况具体分析。


    参考链接

    关于注解@interface的使用

    Spring 常见注解原理和自定义@interface注解

    Android 进阶之自定义注解


    技术永不眠!我们下期见!

  • 相关阅读:
    手机远程控制plc有什么优势
    代码规范:C++函数的高级特性
    EMR Serverless Spark:一站式全托管湖仓分析利器
    聊聊Spring中的事务
    django中静态资源配置
    ORA-28001:the password has expired,Linux上修改Oracle密码
    Python编程从入门到实践 第八章:函数 练习答案记录
    3D高斯泼溅(Splatting)简明教程
    Go 接口-契约介绍
    leetcode725. 分隔链表(java)
  • 原文地址:https://blog.csdn.net/csdnzouqi/article/details/126224422