android进阶---【注解(一)之运行时注解】

2023-05-16

android进阶---注解

  • 注解
    • 1.什么是注解
    • 2.注解的产生
    • 3.注解的基础介绍
      • 3.1元注解
      • 3.2运行时注解与编译时注解区别
    • 4.自定义注解
      • 4.1自定义编写规则
      • 4.2自定义运行时注解

注解

注解这个概念,有些人可能会有些陌生。但是撸过代码的人应该都见过@Override,有用过ButterKnife,Glide,GreenDao等等这些框架,当不用再写那么多行的findViewById,不用再为图片三级缓存加载而挠头,不再为写一条复杂的sql语句而烦恼的时候,我们不觉得对这些框架竖起了大拇指,感觉他们就像神灵一般解救我们于水火,而不敢去了解和深入他们。但是,如果知道了他们的原理,你会发现,我们也可是是神灵的缔造者。

1.什么是注解

注解(Annotation),也叫元数据(即描述数据的数据),一种代码级别的说明。
它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
说了一大堆,其实,就是比注释还牛逼的注释。
我们知道,注释是不会干预程序的执行的,注解同样不能影响代码的实际逻辑,但却可以起到辅助性的作用。

反正,就是很牛逼的。
比如:生成文档,像@param,@Document;编译检查,像Override;跟踪代码依赖性,替代配置文件,像eventBus,ButterKnife等。总之就是牛逼,就够了。

2.注解的产生

注解起源于java1.5,起初作用基本类似是加强型的注释语言,为了编译检查,增强可阅读性,比如@Override: 检查是否正确重写;@Deprecated: 表示该函数已弃用,会划一条横线;@NonNull: 检查参数非空。空指针可以在编译时发现,而不必等到运行时抛出NullPointerException。

java1.6 的时候,官方推出了一个插入式注解处理API(有兴趣可以看下java新特性有兴趣可以看下java新特性:https://blog.csdn.net/sysmedia/article/details/53608681)。指的注意的是,对注解的处理不仅运行时可以处理,还可以在编译期处理,通过注解处理器生成新的java代码并加入到编译中。
一句话: 我们能用java注解自动生成java文件了。 哎呦,这个屌!不错呦!

这里插播一句,著名的butterknife框架,在早期的时候,使用的应该是运行时注解,所以,在效率性能方面会有影响。但是后期,JakeWharton修改为编译期注解,这样对程序的运行就不存在性能问题了。(因为早期听别人说,butterknife会影响性能,所以一直没有用,常年来一直在不停的findViewById,在慢慢的了解了注解后,才知道,大神早已经把性能的问题解决了,我才放心大胆的用了)

3.注解的基础介绍

3.1元注解

元注解,其实就是修饰注解的注解。

看下@Override 的定义,咱们就知道了

package java.lang;

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

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@Override本身是一个注解,但是它的定义上还有 @Target@Retention 在修饰它,那么 像这两个用来 专门修饰注解的注解 就叫做元注解。

目前比较常见的元注解有:

  • @Retention:注解保留的生命周期
    参数作用周期
    RetentionPolicy.SOURCE只在源码中有效,编译时抛弃,如@Override
    RetentionPolicy.CLASS编译期注解
    RetentionPolicy.RUNTIME运行期注解

编译期注解 在class文件中可用,能够存于编译之后的字节码之中(编译时注解能够自动处理Java源文件并生成更多的源码、配置文件、脚本或其他可能想要生成的东西。这些操作是通过注解处理器完成的。Java编译器集成了注解处理、通过在编译期间调用javac -processor命令可以调起注解处理器,它能够允许我们实现编译时注解的功能,从而提高函数库的性能。)该注解的注册信息会保留在.java源码里和.class文件里,在执行的时候,会被Java虚拟机丢弃,不会加载到虚拟机中。

运行期注解 VM在运行期也会保留注解,因此运行期注解可以通过反射获取注解的相关信息(运行时注解一般和反射机制配合使用,相比编译时注解性能比较低,但灵活性好,实现起来比较简答。)Java虚拟机在运行期也保留注解信息,可以通过反射机制读取注解的信息(.java源码,.class文件和执行的时候都有注解的信息)

  • @Target:注解对象的作用范围。

    参数作用范围
    ElementType.TYPE类、接口、枚举、注解类型
    ElementType.FIELD类成员属性(构造方法、方法、成员变量)
    ElementType.METHOD方法
    ElementType.PARAMETER参数
    ElementType.CONSTRUCTOR构造参数
    ElementType.LOCAL_VARIABLE局部变量
    ElementType.ANNOTATION_TYPE注解
    ElementType.PACKAGE
    ElementType.TYPE_PARAMETER类型参数
    ElementType.TYPE_USE类型使用说明
  • @Inherited:标明所修饰的注解,在所作用的类上,是否可以被继承。

注解所作用的类,在继承时默认无法继承父类的注解。除非注解声明了 @Inherited。同时Inherited声明出来的注解,只对类有效,对方法/属性无效。

  • @Documented:如其名,javadoc的工具文档化

如其名,javadoc的工具文档化,一般不关心。

  • @Repeatable:表示这个注解可以在同一个项上面应用多次(java8)

3.2运行时注解与编译时注解区别

运行时注解 一般和反射机制配合使用,相比编译时注解性能比较低,但灵活性好,实现起来比较简单。并不是说为了性能运行期注解就不能用了,只能说不能滥用,要在性能方面给予考虑。目前主要的用到运行期注解的框架差不多都有缓存机制,只有在第一次使用时通过反射机制,当再次使用时直接从缓存中取出。
编译时注解 能够自动处理Java源文件并生成更多的源码、配置文件、脚本或其他可能想要生成的东西。通过注解处理器完成对注解的解析。Java编译器集成了注解处理器,允许实现编译期注解功能,调高函数库性能。

编译期: 是指把源码交给编译器编译成计算机可以执行的文件的过程.在Java中也就是把Java代码编成class文件的过程.编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误.优化代码神马的。

运行期:是把编译后的文件交给计算机执行.直到程序运行结束.所谓运行期就把在磁盘中的代码放到内存中执行起来。

4.自定义注解

4.1自定义编写规则

  • 注解类型的声明,使用@interface 和元注解进行描述。
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface MyTest {
    String log();
} 
  • 注解的元素是以 接口方法 的形式体现的(但它真的是元素),方法声明不能包含任何参数或 throws,只能用public或默认(default)访问权修饰。
    String log()只表示MyTest这个注解有一个元素叫 log

  • 方法的返回类型 必须是基本数据类型、String、Class、枚举、注解或这些类型的数组,方法可以有默认值(如果没有默认值,必须在属性中设置;Class 默认值不能为null) 如:

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface Hello {
    String name() default "";
}
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface ClickInterval {
    long value() default 1000;
}
  • 如果自定义注解只有一个参数,参数的名字如果是自定义那么,在调用时候,需要写上参数“名称=值”:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyBindView {
     int id() ;
}

调用时:

@MyBindView(id = R.id.tv_test)
public TextView tv_test;

如果参数有且只有一个,且参数名字是value,则,调用时候,可不写参数名称;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyBindView {
     int value() ;
}

调用时:

@MyBindView(R.id.tv_test)
public TextView tv_test;

4.2自定义运行时注解

学习自定义运行时注解前,最好先了解下反射的相关api;

自定义注解 + 注解处理器(会用到java反射机制)

很简单!来做一个弱智版的butterknife吧
先搞个自定义注解:

既然是运行时注解,那 @Retention 就选择 RetentionPolicy.RUNTIME

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyBindView {
     int value() ;
}

再怼个注解处理器:

public class MyButterKnife {
    public static void bindView(Activity activity){
        Class<? extends Activity> clazz = activity.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println("名称: " + field.getName());
            if (field.isAnnotationPresent(MyBindView.class)) {
                MyBindView annotation = field.getAnnotation(MyBindView.class);
                if (annotation != null) {
                    try {
                        field.set(activity, activity.findViewById(annotation.value()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }else {
            }
        }
    }
}

调用,测试下。完事!

public class MainActivity extends AppCompatActivity {

    @MyBindView(R.id.tv_test)
    public TextView tv_test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyButterKnife.bindView(this);
        Test();
    }

    public void Test() {
        tv_test.setText("哈哈哈哈");
    }
}

在这里插入图片描述
但是,如果你想要更高、更快、更强的话,你就需要学会自定义编译期注解

毕竟这么简单的东西,拿出去装逼,有些丢人啊。
如果你想看更加有深度、有内涵、有料的东西,就看下一篇吧!

在此感谢以下文章的内容分享:
Android 自定义注解详解
Android 中优雅地使用注解
Android注解快速入门和实用解析

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android进阶---【注解(一)之运行时注解】 的相关文章

随机推荐

  • 基于ESP32的Bluedroid蓝牙协议栈架构分析(2)--- ADV广播流程分析

    为了分析ESP32的蓝牙接口 xff0c 是如何在协议栈上运行的 xff0c 现在以最简单的启动广播为例 xff0c 分析Bluedroid蓝牙协议栈整体流程 具体数据发生过程如下 xff1a esp ble gap start adver
  • 基于ESP32的nimble-host蓝牙协议栈移植分析

    ESP32蓝牙协议栈NIMBLE HOST协议移植分析 目录 ESP32蓝牙协议栈NIMBLE HOST协议移植分析 一 nimble 蓝牙协议栈介绍 二 关于esp32移植的内容分析 2 1 关于 porting 目录移植 2 2 nim
  • 基于BK蓝牙RW-BLE协议栈调度逻辑梳理

  • A2DP协议总结

  • iOS代码混淆原理初探

    我们在手游平台SDK的iOS版本中 xff0c 除了AppStore官方支付之外还集成了第三方支付 xff08 微信支付H5和支付宝支付H5版本 xff09 如果用于企业签 xff0c 不需要做处理 xff0c 直接使用即可 但是如果需要上
  • (五)Selenium自动化测试实战—PO模式

    nbsp 上一篇 四 selenium自动化测试之上传本地文件 要开朗的spookypop的博客 CSDN博客 selenium上传本地文件 先看下测试代码运行效果 在做自动化测试时 测试框架设计很重要 测试代码写法也很多种 最简单的莫过于
  • git clone 指定某个分支

    原文 xff1a https blog csdn net qq 28903377 article details 82978583 最近在搭建Gitblit内网仓库时发现一个问题 xff0c git clone 只能clone整个仓库 xf
  • B站Unity官方教程合集(不定期更新)

    Unity官方有好多教程 xff0c 可以帮助我们快速掌握这款引擎的使用 xff0c 但官网上的视频都是油管的 xff0c 故这里为大家整合了一些在B站上的搬运视频 xff0c 很多还是有翻译字幕的 xff0c 比搭梯子方便多了 xff08
  • STM32连接HT1621段码屏驱动

    HT1621 128个位元LCD控制器 xff0c 内部RAM直接对应LCD显示单元 对于HT1621 操作之前应发送标志码 xff0c 表明要求工作在哪种状态 xff0c 标志定义如下 xff1a 操作状态标志码读数据110写数据101读
  • RTK与PPK

    1 通讯方式不同 RTK技术需要无线电台或网络来传输差分数据 PPK技术不需要通信技术的支持 xff0c 并且可以记录静态数据 2 定位方法不同 RTK所使用的实时定位技术使您可以随时在流动站上查看测量点的坐标和精度 xff1b PPK定位
  • iOS真机调试报错(0xE8008016)相关错误

    经常真机运行时候会报错 xff0c 原因之一是之前对项目进行过打包进行如下设置 将Edit Scheme gt Run gt Build Configuration 设置为Release 将其勾选为 Debug状态 xff0c 接下来继续运
  • 支付宝快捷登录相关事宜

    接近年关 xff0c 公司产品提出新需求 xff0c 和支付宝合作 xff0c 需要开发快捷登录 无线账户授权 xff0c 手机端装有支付宝钱包 xff0c 直接唤起支付宝钱包 xff0c 若没有支付宝钱包就直接走HTML5页面操作 xff
  • mac系统Tunnelblick 下载以及安装流程

    公司有些网站有权限设置 xff0c 不同的域账号权限不一样 xff0c 因此需在电脑上安装Tunnelblick xff0c 才能使用 xff0c 接下来给大家介绍一下步骤 xff1a 首先要有安装vpn对应的一系列配置文件 xff1a c
  • IOS App提交到appStore Missing 64-bit support

    Dear developer We have discovered one or more issues with your recent delivery for 34 就医宝 34 Your delivery was successfu
  • MAC 安装cocoapods

    首先是看了文章 xff1a http code4app com article cocoapods install usage http www uml org cn mobiledev 201411072 asp 一 检测以及配置Ruby
  • U8SDK——开发统一的手游防沉迷插件

    关于统一防沉迷插件的配置和使用 xff0c 可以参考我们B站上面录制的视频教程 未满18岁那个视频 xff1a U8SDK官方视频 根据手游防沉迷和实名认证政策的要求 xff0c 手机游戏需要引导玩家进行实名认证 xff1b 同时针对未成年
  • Unable to run app in Simulator(Domain = LaunchServicesErrror, Code = 0)

    NSArray paths 5 61 NSSearchPathForDirectoriesInDomains NSLibraryDirectory NSUserDomainMask YES Users hkqj Library Develo
  • 微信支付登录总结

    做微信支付 xff0c 登录之前需要 提前注册开发者帐号 xff0c 创建移动应用 代码下载路径 xff1a http pan baidu com s 1o7aBxqU xff08 主要是做笔记 xff0c 把微信登录以及微信支付整到一起
  • 微软仿真神器 AirSim + Unreal Engine 4.24 + Ubuntu 18.04 + ROS 编译流程小结

    时间 xff1a 20210107 文章目录 一 参考资料二 系统情况简介三 编译UE引擎流程四 UE引擎测试五 AirSim编译流程六 UE 4 24 43 AirSim 联合测试七 AirSim 的 ROS 功能包测试八 UE 43 R
  • android进阶---【注解(一)之运行时注解】

    android进阶 注解 注解1 什么是注解2 注解的产生3 注解的基础介绍3 1元注解3 2运行时注解与编译时注解区别 4 自定义注解4 1自定义编写规则4 2自定义运行时注解 注解 注解这个概念 xff0c 有些人可能会有些陌生 但是撸