这篇文章 2016年12月13日星期二 就写完了,当时想着等写完另外一篇关于自定义注解的一起发。结果没想到这一等就是半年多 - -。

有时候的确是这样啊,总想着等条件更好了再干,等准备完全了再开始,结果好多想法、好多事情都不了了之。

读完本文你将了解:

  • 什么是注解
  • Java 内置的注解
    • 个用于通知编译器信息的注解
    • 个用于修饰注解的注解
  • 自定义一个注解
  • 注解的作用
  • 注解的用法
  • 运行时注解
  • 总结
  • Thanks

什么是注解

注解是一种元数据(描述数据的数据)

描述作用,不会直接生效,需要在编译前/运行时获取注解信息
代码检查

注解简单的说就是以 @ 开头的一个字符串,在 Android Studio 默认是黄色高亮,比如下面的 @Override:

这里的 @Override 没有值,只是一个修饰作用,告诉编译器这个方法要覆盖父类的方法,编译器会去检查父类有没有这个方法。

我们在使用注解时可以传入更详细的内容,使用 “key1=value1, key2=value2”的格式传入,比如:

@Author(name = "shixinzhang", date = "2016.12.13")
public class AnnotationTestActivity extends BaseActivity {...}

@Author 注解内部有两个字符串,分别为 name, date:

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface Author {String name();String date();
}

当注解的属性只有一个时,可以命名为 value,这样在使用时可以使用快捷方式 – 直接传入值,而不是声明属性名,比如下面的 @ContentView,只有一个名称为 value() 的属性:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContentView {//属性叫 value ,在使用时可以直接传参数即可,不必显式的指明键值对,是一种快捷方法int value();
}

使用时直接传参数,不必指明属性名:


@Author(name = "shixinzhang", date = "2016.12.13")
@ContentView(R.layout.activity_annotation)
public class AnnotationTestActivity extends BaseActivity {...}

Java 内置的注解

上面的两个自定义注解用到了 @Retention, @Target,它们其实是 Java 内置的注解,方便我们使用。

Java 内置的注解主要有 9 个,分为位于 java.lang or java.lang.annotation 包下。

5 个用于通知编译器信息的注解:

  • @Override :空注解,用于标记那些覆盖父类方法的方法,如果父类没有这个方法,或者复写的方法访问权限比父类的权限小,编译器就会报错
  • @Deprecated : 空注解,用于标记那些不应该被使用的代码,如果使用了过时的代码,编译器会发出警告
  • @SafeVarargs : 空注解,(varargs 可变参数)用于标记构造函数或者方法,通知编译器,这里的可变参数相关的操作保证安全
  • @FunctionInterface : Java SE 8 出现的,用于通知编译器,这个类型是 function 接口
  • @SuppressWarning:抑制错误,可以用于标记整个类、某个方法、某个属性或者某个参数,用于告诉编译器这个代码是安全的,不必警告
    • 强烈建议最小范围使用这个注解,一旦你在一个比较大的范围抑制错误,可能会把真正的问题掩盖了

@SuppressWarning 支持的参数如下及使用方式见这篇 @SuppressWarning 使用及支持的参数.

4 个用于修饰注解的注解:

修饰其他注解的注解称为“元注解”。

  • @Documented:让注解信息出现在 document 中
  • @Retention : 指出注解如何存储,支持以下三种参数
    • RetentionPolicy.SOURCE : 注解只保留在源码中,编译时会忽略
    • RetentionPolicy.CLASS : 更高一级,编译时被编译器保留,但是运行时会被 JVM 忽略
    • RetentionPolicy.RUNTIME : 最高级,运行时会被保留,可以被运行时访问
  • @Target :指出注解作用于(修饰)什么对象,支持以下几种参数
    • ElementType.TYPE : 作用于任何类、接口、枚举
    • ElementType.FIELD : 作用于一个域或者属性
    • ElementType.METHOD : 作用于一个方法
    • ElementType.PARAMTER : 作用于参数
    • ElementType.CONSTRUCTOR : 作用于构造函数
    • ElementType.LOCAL_VARIABLE : 作用于本地变量
    • ElementType. ANNOTATION_TYPE : 作用于注解
    • ElementType.PACKAGE : 作用于包
  • @Inherited :当前注解是否可以继承

自定义一个注解

创建注解时,需要声明的类型为 @interface,看起来和接口有一些相似哈,其中的 @ 标明这是一个注解类型( “at ~ annotation type”):

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContentView {//属性叫 value ,在使用时可以直接传参数即可,不必显式的指明键值对,是一种快捷方法int value();
}

注解除了名字和接口有些相似,内容也很相似,都是声明一个方法,规定返回值,不同的是这里的方法其实是个属性,返回值规定了属性的类型(至于为什么要声明成方法而不是属性,可能是为了后续直接使用这个方法获取值比较直观吧)。

注意:如果你的注解中创建了多个属性,但是使用时只需要使用某几个,这时编译器会提示你有没有指明的属性。

我们可以使用 default … 为注解的某个属性指定默认值,这样即使不指定某个属性,编译器也不会报错。这通常可以节约很多时间,比如这样:

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface Author {String name() default "shixinzhang";String date();
}

当我们使用 @Author 时没有指定 name = XXX,则会默认为 “shixinzhang”。

注解的作用

注解可以用来修饰类、方法、参数等等,具体的使用场景有以下三种:

  1. 编译前提示信息:注解可以被编译器用来发现错误,或者清除不必要的警告;
  2. 编译时生成代码:一些处理器可以在编译时根据注解信息生成代码,比如 Java 代码,xml 代码等;
  3. 运行时处理:我们可以在运行时根据注解,通过反射获取具体信息,然后做一些操作。

注解的用法

  • 自定义注解:规定处理对象类型,保存阶段,以及包含的值
  • 使用注解修饰我们想要的处理的类、方法或者属性
  • 读取注解,使用注解处理器处理

注解处理器分为两种:

  • 运行时处理器
  • 编译时处理器

先介绍简单的一种:运行时注解处理器。

运行时注解

运行时注解需要使用 注解 + 反射 ,非常简单。

我们先自定义一个 ContentView 注解,表示当前布局对应的 layout 文件:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContentView {//属性叫 value ,在使用时可以直接传参数即可,不必显式的指明键值对,是一种快捷方法int value() ;
}

然后用它修饰一个 Activity:

@ContentView(R.layout.activity_annotation)
public class AnnotationTestActivity extends BaseActivity {@Overrideprotected void onCreate(@Nullable final Bundle savedInstanceState) {super.onCreate(savedInstanceState);  //调用父类的 onCreatesetContentView(R.layout.activity_annotation);}
}

在 BaseActivity 中反射获取当前类使用的注解,拿到注解的值,就可以直接设置布局了:

    @Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);annotationProcess();}//读取注解,进行处理private void annotationProcess() {Class c = this.getClass();//遍历所有子类for (; c != Context.class; c = c.getSuperclass()) {//找到使用 ContentView 注解的类ContentView annotation = (ContentView) c.getAnnotation(ContentView.class);if (annotation != null) {try {   //有可能出错的地方都要 try-catch//获取 注解中的属性值,为 Activity 设置布局this.setContentView(annotation.value());} catch (RuntimeException e) {e.printStackTrace();}return;}}}

这样就简单实现了运行时根据注解动态设置布局的功能。

总结

黑科技、低性能

使用注解往往可以实现用非常少的代码作出匪夷所思的事情,比如 ButterKnife。

但被人诟病的是,运行时注解需要使用大量 Java 反射而引起较为严重的性能问题。

在使用运行时注解时需要小心,在调用方法时注意对异常的捕获,避免调用失败。

下一篇文章我们了解更为高性能的注解:使用编译时注解简单实现类似 ButterKnife 的效果。

Thanks

https://docs.oracle.com/javase/tutorial/java/annotations/index.html

http://tutorials.jenkov.com/java/annotations.html

http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html

http://blog.csdn.net/duo2005duo/article/details/50505884

http://lrd.ele.me/2016/07/17/%20Android%E7%BC%96%E8%AF%91%E6%97%B6%E6%B3%A8%E8%A7%A3%E6%A1%86%E6%9E%B6%E7%B3%BB%E5%88%971-%E4%BB%80%E4%B9%88%E6%98%AF%E7%BC%96%E8%AF%91%E6%97%B6%E6%B3%A8%E8%A7%A3/

Java 进阶巩固:什么是注解以及运行时注解的使用相关推荐

  1. java 注解 runtime_自定义注解之运行时注解(RetentionPolicy.RUNTIME)

    对注解概念不了解的可以先看这个:Java注解基础概念总结 前面有提到注解按生命周期来划分可分为3类: 1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成clas ...

  2. java只修改变的字段_java注解之运行时修改字段的注解值操作

    今天遇到需求:导入Excel时候列头会发生变化,客户是大爷要求你改代码, 导入Excel是用easypoi做的,识别表头是用注解@Excel(name = "xxx")通过这个na ...

  3. java通过注解修改字段名_java注解之运行时修改字段的注解值操作

    java注解之运行时修改字段的注解值操作,注解,字段,表头,属性,对象 java注解之运行时修改字段的注解值操作 易采站长站,站长之家为您整理了java注解之运行时修改字段的注解值操作的相关内容. 今 ...

  4. 使用AIDL+动态代理+运行时注解+反射 反手撸一套Android跨进程通信框架

    IPC 前言 跨进程通信方式 跨进程通信框架 涉及到的技术 使用Request-Response思想 IPCRequest IPCResponse RemoteService 服务端 客户端 附带 项 ...

  5. java导出jar包后,程序运行时读取图片、音乐资源文件

    java导出jar包后,程序运行时读取图片.音乐资源文件 运行时程序就可以把图片.音乐资源加载进入了 start jre/bin/java -jar 名称.jar

  6. 注解(一)- 基础知识与运行时注解

    在java和android 中,注解的运用非常广泛,很多的类库,第三方框架中都用到了注解.所以我们有必要来熟悉注解的相关知识. Annotation,注解(也称为元数据),可以为我们在代码中添加额外的 ...

  7. java虚拟机栈帧_Java虚拟机,运行时栈帧结构

    业余生活要有意义,不要越轨.--华盛顿 引导语 "虚拟机"是一个相对于"物理机"的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器. ...

  8. Java反射运行时_java反射获得运行时属性的值

    运行时动态获得属性的值(通过方法获得): Method[] methods = cls.getDeclaredMethods(); for (Method method : methods) { if ...

  9. maven java版本过低_maven项目编译运行时提示jdk版本过低问题解决方法

    明明使用的是1.8jdk,但是运行项目时提示使用的是java版本是1.5,版本过低. 修改pom.xml,添加如下: maven-compiler-plugin 3.6.1 1.8 1.8 UTF-8 ...

最新文章

  1. xp启动java设置_Windows XP快速启动经典六招
  2. JS 全局对象 全局变量 作用域 (改自TOM大叔博文)
  3. 8、MySQL注释:单行注释和多行注释
  4. Java笔记-ReadWriteLock与Condition的使用
  5. MySQL IS NULL(IS NOT NULL)使用索引分析
  6. centos调整页面大小_新手教程!设置PDF文件的页面大小
  7. Linux 系统批量安装字体的方法
  8. pe_xscan作了3点更新 1
  9. Chrome 手动清理缓存
  10. BetaFlight模块设计之十三:Gyro过滤任务分析
  11. FPGA2016~2018,FPL2017会议论文整理(持续更新)
  12. .bat 是什么? (批处理脚本)
  13. 淘宝关注的主播查询教程(2021)
  14. 【python二级-练习题】
  15. 题解:luogu P2634 [国家集训队]聪聪可可
  16. 微信小程序上传图片至服务器Springboot接收格式的问题
  17. ECharts-Javascript的图表库推荐
  18. 二维码生成 单个下载 批量打包下载
  19. if-else 语句优雅处理
  20. CAD绘制三维图形基础

热门文章

  1. 计算机职一知识点,计算机一级知识点.doc
  2. 12自由度六足机器人实现原地舞蹈功能
  3. python位置参数要按顺序传吗,中国大学MOOC: 在Python调用函数时,明确指定哪个值传递给哪个参数,实参顺序和形参顺序不一致时,按位置顺序传递数据。 答案:错...
  4. (论文分析)基于深度强化学习方法的有效边缘学习激励机制设计
  5. Java之GUI 简易贪吃蛇
  6. 如何测试微信好友是否删除或者拉黑了自己
  7. 蜗牛学院教材 12道经典案例题
  8. 中兴助Zeop测试10Gbps宽带服务
  9. php java 哪个难,php和java的区别在哪里,那个更难一些
  10. 从一年看不完1本书,到半年读完30本,我是怎么做到的?