当前位置: 首页 > 编程日记 > 正文

Android -- Annotation(注解)原理详解及常见框架应用

1,我们在上一篇讲到了EventBus源码及3.0版本的简单使用,知道了我们3.0版本是使用注解方式标记事件响应方法的,这里我们就有一个疑问了,为什么在一个方法加上类似于“@Subscribe”,就可以让我们的反射找到我们的事件响应方法。而且使用过BufferKnife、Dagger、Retrofit的同学或常见“@XXX”这种关键字 。so,抱着弄懂一切不明真相的精神,我们开始了这篇文章的探索。

2,什么是注解?

  它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。

  ok,知道大家对上面的注解定义现在是一脸懵逼,所以举一个创建的栗子吧,“@Override”关键字我们熟悉吧,我们创建Activity的时候,重写onCreate方法,方法上面就有这个标记,拿我们看一下它的源码是什么

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

 "Target"、"Rentention" 这些什么是一些什么啊 ,感觉懵逼加重。如果我们自己写一个方法,然后在上面加上一个"@Override",看一下效果

 看到没,直接就报错了,所以我们在想,到底什么时候才能使用“@Override”关键字?能不能使用类似于“A”、“B”关键字?拥有这些标记的方法、属性、类有什么用啊?所以带着这些问题我们先来了解简单的常理知识。

  • 元注解

  看到这个名字可能同学们都有点蒙了,学过Python的同学肯定知道元数据。但是这里和我们的元数据没有一毛钱关系,定义也很简单,"Java中提供了四个元注解,专门注解其它注解。" 

   @Documented –注解是否将包含在JavaDoc中@Retention –什么时候使用该注解@Target –注解用于什么地方@Inherited – 是否允许子类继承该注解

 咦,看着上面的Retention 、Target  这不是我们"@Override"关键字中见过吗,哦,现在知道了它们对应的是什么意思了,让我们具体的看一下四个元注解的详细信息吧

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

这个很简单,我们看看EventBus3.0的@Subscribe的源码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {ThreadMode threadMode() default ThreadMode.POSTING;/*** If true, delivers the most recent sticky event (posted with* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).*/boolean sticky() default false;/** Subscriber priority to influence the order of event delivery.* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of* delivery among subscribers with different {@link ThreadMode}s! */int priority() default 0;
}

 果然,这里使用了我们的@Documented元注解了,我们继续往下看

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

 我们这时候有个疑问,当我们的这个字段值为true的时候,并修饰的我们的class类表示的什么。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

  • @Target 

  这个注解表示注解的作用范围,主要有如下:

ElementType.FIELD 注解作用于变量ElementType.METHOD 注解作用于方法ElementType.PARAMETER 注解作用于参数ElementType.CONSTRUCTOR 注解作用于构造方法ElementType.LOCAL_VARIABLE 注解作用于局部变量ElementType.PACKAGE 注解作用于包

 而我们常见的基本上适用于变量、方法,这里给大家举例一下Retrofit2.0中的"@Query"注解,这是使用的就是PARAMETER 作用于参数,源码如下:

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Query {/** The query parameter name. */String value();/*** Specifies whether the parameter {@linkplain #value() name} and value are already URL encoded.*/boolean encoded() default false;
}
  • @Retention 

  这个表示注解的保留方式,具体有一下三种类型

  RetentionPolicy.SOURCE : 只保留在源码中,不保留在class中,同时也不加载到虚拟机中 。在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。RetentionPolicy.CLASS : 保留在源码中,同时也保留到class中,但是不加载到虚拟机中 。在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式RetentionPolicy.RUNTIME : 保留到源码中,同时也保留到class中,最后加载到虚拟机中。始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

ok,把以上四种元数据的概念都弄懂了之后,我们在看我们之前看的"@Override"源码

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

  表示该注解作用于方法,且只保存在源码中。

  ok,再看一下我们Java中常见的注解有哪些吧,这里只用了解了解

@Override: 表示该方法是重写父类中的方法,编译的时候会检查该方法,如果这个方法不是父类中存在的将会报错
@Deprecated: 表示该方法时已经过时的,表示该方法有风险或者有更好的替代方法
@SuppressWarnings: 表示在编译的时候忽略某种错误,如版本检查等

 这里还有一个疑问,我们的程序是怎么知道某个类中包含注解方法的呢?又是在获取注解方法中的相应属性的呢?

  这里我们使用反射来拿到class中的注解方法,主要使用这句关键代码

method.getAnnotation(XXXAnnonation.class)

3,自定义注解

  我们上面了解了一系列注解知识,现在我们想自定义自己的注解,作用于方法,注解里面的属性有name和id,所以我们代码如下:

package com.qianmo.eventbustest;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** Created by wangjitao on 2017/4/14 0014.* E-Mail:543441727@qq.com*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnonation {String name() default "";int id() default 0;
}

然后在Activity中标记我们自己编写的方法,设置annonation的属性

  @TestAnnonation(name = "wangjitao", id = 1)public void testMothed() {tv_message.setText(name + ":" + id);}

 提供反射的方法拿到Annonation中对应的属性,保存数据

 private void getAnnonationData(Class clazz) {Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {TestAnnonation testAnnonation = method.getAnnotation(TestAnnonation.class);if (testAnnonation != null) {name = testAnnonation.name();id = testAnnonation.id();}}}

完整代码如下:

public class MainActivity extends AppCompatActivity {private Button btn_skip;private TextView tv_message;private String name;private int id;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_skip = (Button) findViewById(R.id.btn_skip);tv_message = (TextView) findViewById(R.id.tv_message);btn_skip.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {testMothed();}});getAnnonationData(MainActivity.class);}@TestAnnonation(name = "wangjitao", id = 1)public void testMothed() {tv_message.setText(name + ":" + id);}private void getAnnonationData(Class clazz) {Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {TestAnnonation testAnnonation = method.getAnnotation(TestAnnonation.class);if (testAnnonation != null) {name = testAnnonation.name();id = testAnnonation.id();}}}}

效果如下:

ok,今天就给大家普及到这里,搞懂了以上的注解知识之后,我们看Retrofit2.0的 @GET、@POST等还有难度吗?  小伙子们赶紧去看看来弄懂之前没搞懂的注解原理吧。。。。

相关文章:

简单工厂模式(StaticFactoryMethod)

来华北电力大学数理系LSGO软件技术团队学习Coding,我通常第一个就讲“简单工厂模式”,这一讲不仅仅是讲模式,更主要的是让大家体会什么是软件系统的“可复用”、“可扩展”、“易维护”、“灵活性好”,以及如何通过面向对象程序设…

Html,Css,Javascript是什么?

本文属于基础科普文,高富帅们请绕道吧。 Html,css,javascript是做网页前台设计的标准套装,html是一些网页控件,css是美化这些控件的代码(层叠样式表),js(javascript&…

[转帖]ERP术语

栖息谷-IT管理-[转帖]ERP术语 [转帖]ERP术语 1 英文缩写: MIS 英文全称: Management Information System 中文翻译: 管理信息系统 简释: MIS是指对企业大量的原始管理…

how tomcat works 总结 二

第五章 servlet容器 第 5 章讨论 container 模块。container 指的是 org.apache.catalina.Container 接口,有4 种类型的 container:engine, host, context 和 wrapper。这章提供了两个工作于 context 和wrapper 的程序。容器共分四类,类图例如以下:一个wrapper就是一…

策略模式(Strategy)

这是来数理系LSGO软件技术团队学习Coding,第二个要学习的设计模式。该模式在解决同一个问题时可以使用不同的算法。以满足“开闭原则”,把各种算法与实际业务逻辑解耦合,以便写出良好的代码。

[scrum]2011/9/22-----第二天

scrum 总结: Team member Yesterday’s Work Today’s Work Issue R X Task196:Completed xml 文件的解析,并且通过了两个测试用例 Task198:Completed 添加全局变量:当前会议和remind list Task201:Active 基本完成了select …

千千静听4.6.7版发布了

现在这个版本算是很不错的了,提供了相当完善的播放功能 下载: http://ttplayer.com/ttpsetup.exe 转载于:https://www.cnblogs.com/it201108/archive/2006/04/29/2148385.html

Strategy_Requirement1

以下代码是“策略模式”的第一个例子:

代码解说Android Scroller、VelocityTracker

在编写自己定义滑动控件时经常会用到Android触摸机制和Scroller及VelocityTracker。Android Touch系统简单介绍(二):实例具体解释onInterceptTouchEvent与onTouchEvent的调用过程对Android触摸机制须要用到的函数进行了具体的解释。本文主要介绍两个重要…

写给云栖社区在做网站的朋友一点干货

我本人也是从事网站建设及APP开发业务的,工作多年下来,从以前的几百元企业网站,到商城网站,以及一些应用类型的APP开发,亲眼目睹了很多企业,以及很多项目,在应用的过程中,过了1-2年&…

Strategy_Requirement2

以下代码是“策略模式”的第二个例子:

如何启用SQL Server 2008的FILESTREAM特性

如何启用SQL Server 2008的FILESTREAM特性 今天安装SQL Server 2008的时候没有注意,忘记了启用FILESTREAM特性,因为默认情况下FILESTREAM是禁用的。安装完成后,再导入一个.bak的备份数据库时提示FILESTREAM feature is disabled,到…

如何在搜索结果出来之前,让页面显示“等待中。。。”

在当前页面点击搜索按纽后,当前页的button onclick事件会生成一个sql语句,然后转到查询结果页面,由于查询可能很费时间,客户要求在这两个页面中加入一个提示用户正在查询,请等待的页,具体的查询是在查询结果…

Strategy_Level1

以下代码是“策略模式”的第三个例子:

波士顿房价预测学习项目笔记

机器学习入门项目 作为机器学习的入门项目,了解到这个一个监督学习类型的回归问题模型。项目中需要根据已有的数据,构建一个合理的模型对未来的房价可以做出预测。 Udacity机器学习课程针对初学者做了精心地设计,这里来看项目是如何组织的&am…

LINQ之路19:LINQ to XML之X-DOM更新、和Value属性交互

本篇包含两部分内容:X-DOM更新一节中我们会详细讨论LINQ to XML的更新方式,包括Value的更新、子节点和属性的更新、通过Parent节点实现更新; 和Value属性交互一节会详细讨论XElement和XAttribute的Value属性。如果一个元素只有单个XText子节点…

明朝是中国历史上最有骨气的王朝?【ZZ】

linked from http://www.guoxue.com/article/list.asp?id6095明朝是中国历史上最有骨气的王朝?作者: (国学网2006-5-12发布) 有人对明朝极尽污蔑之能事,好象明朝是最不中用的朝代。其实,只要细心比较&am…

马哥第七次作业

系统的INPUT和OUTPUT默认策略为DROP,请完成以下关于iptables的题目;1、限制本地主机的web服务器在周一不允许访问;新请求的速率不能超过100个每秒;web服务器包含了admin字符串的页面不允许访问;web服务器仅允许响应报文…

Strategy_Pattern

以下代码是“策略模式”的第四个例子:

JAVA-基础(Class对象及反射)

JAVA-基础(Class对象及反射) 1.(1)什么是class对象? 首先,java有两种对象,第一种是实例对象,第二种是Class对象,每一个类运行的类型信息就是用Class对象表示的&#xff0…

当年学生的一件事,心情很难过

当年学生的一件事,心情很难过 今天同一个以前的学生聊天,搞得心情很难过。那年是刚毕业,带了几个学生的毕业论文,其中有一个,只是第一次见过一面,最后答辩前见一两天以及答谢见过一面。他从来不同我联系&am…

while循环中,break,continue,return的差别

break 结束循环,跳出循环体;continue 结束本次循环。进行下次循环;return 跳出循环体所在的方法,相当于跳出循环体。

Strategy_Level2

以下代码是“策略模式”的第五个例子:

自制绘图之坐标轴

写代码之前得先了解坐标轴的一些属性,坐标轴有范围,每隔多少显示一条数值信息。然而间隔信息有时并不确定,一旦设置不准确,图形会乱掉。最好的方法是使用另一个参数:分隔符总数。这样可以利用坐标范围计算出间隔。 首先…

DotNET(C#) Socket基本编程 (1)

Socket基本编程 服务端: using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; Thread mythread ; Socket socket; // 清理所有正在使用的资源。 protected override void Dispose( bool disposing ) { try {    socket.Clos…

CC2540 OSAL 学习其中原理,以及 给任务 添加 一个事件(定时发送串口消息)

参考学习大神博客: http://blog.csdn.net/feilusia/article/details/51083953 : http://blog.csdn.net/xiaoleiacmer/article/details/41723583 1、TI 的 CC2540跑了一个 OSAL (Operating System Abstraction Layer) 心得:大概 就是 一个循…

Strategy_Level3

以下代码是“策略模式”的第六个例子:

SDK开发日积月累(二)

WM_NOTIFY消息和WM_COMMAND消息在一个对话框中,子控件可以有两种方式与父对话框通信。1.向父对话框发送WM_COMMAND消息,但这种消息传递的信息量比较少。2.向父对话框发送WM_NOTIFY消息,信息量比较大。idCtrl (int) wParam; pnmh (LPNMHDR) …

关于IP地址的分类

我们说过因特网是把全世界的无数个网络连接起来的一个庞大的网间网,每个网络中的计算机通过其自身的IP地址而被唯一标识的,据此我们也可以设想,在INTERNET上这个庞大的网间网中,每个网络也有自己的标识符。这与我们日常生活中的电…

Visual Studio UML Activity Diagram(1)

数理系LSGO软件技术团队能够存活下来,并形成战斗力的根本原因,归结为我们的价值观。我们“只问收获,不问耕耘”,对知识是贪婪的,我们会把所学的知识放到场景中去应用,我们一定要做出成品。我们强调“要构建…