前言:

最近学习了EventBus、BufferKinfe、GreenDao、Retrofit 等优秀开源框架,它们新版本无一另外的都使用到了注解的方式,我们使用在使用的时候也尝到不少好处,基于这种想法我觉得有必要对注解有个更深刻的认识,今天中午把公司的项目搞完了,晚上加个班学习总结一下Java的注解。

什么是注解?

对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

注解的用处:

1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等

2、跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2依赖注入,未来java开发,将大量注解配置,具有很大用处;

3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

元注解:

java.lang.annotation提供了四种元注解,专门注解其他的注解:

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

1.)@Retention– 定义该注解的生命周期
  • RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
  •   RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
  •   RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

举例:bufferKnife 8.0 中@BindView 生命周期为CLASS

@Retention(CLASS) @Target(FIELD)
public @interface BindView {
/** View ID to which the field will be bound. */
@IdRes int value();
}
2.)Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType参数包括
  • ElementType.CONSTRUCTOR:用于描述构造器
  • ElementType.FIELD:成员变量、对象、属性(包括enum实例)
  • ElementType.LOCAL_VARIABLE:用于描述局部变量
  • ElementType.METHOD:用于描述方法
  • ElementType.PACKAGE:用于描述包
  • ElementType.PARAMETER:用于描述参数
  • ElementType.TYPE:用于描述类、接口(包括注解类型) 或enum声明

举例Retrofit 2 中@Field 作用域为参数

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Field {
String value(); /** Specifies whether the {@linkplain #value() name} and value are already URL encoded. */
boolean encoded() default false;
}
3.)@Documented–一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。
4.)@Inherited – 定义该注释和子类的关系

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

常见标准的Annotation:

1.)Override

java.lang.Override是一个标记类型注解,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。

2.)Deprecated

Deprecated也是一种标记类型注解。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。所以使用这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。

3.)SuppressWarnings

SuppressWarning不是一个标记类型注解。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。

@SuppressWarnings("unchecked") 

自定义注解:

这里模拟一个满足网络请求接口,以及如何获取接口的注解函数,参数执行请求。

1.)定义注解:

@ReqType 请求类型

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface ReqType { /**
* 请求方式枚举
*
*/
enum ReqTypeEnum{ GET,POST,DELETE,PUT}; /**
* 请求方式
* @return
*/
ReqTypeEnum reqType() default ReqTypeEnum.POST;
}

@ReqUrl 请求地址

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface ReqUrl {
String reqUrl() default "";
}

@ReqParam 请求参数

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface ReqParam {
String value() default "";
}

从上面可以看出注解参数的可支持数据类型有如下:

1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
    2.String类型
    3.Class类型
    4.enum类型
    5.Annotation类型
    6.以上所有类型的数组

而且不难发现@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

2.)如何使用自定义注解
public interface IReqApi {

    @ReqType(reqType = ReqType.ReqTypeEnum.POST)//声明采用post请求
@ReqUrl(reqUrl = "www.xxx.com/openApi/login")//请求Url地址
String login(@ReqParam("userId") String userId, @ReqParam("pwd") String pwd);//参数用户名 密码 }
3.)如何获取注解参数

这里强调一下,Annotation是被动的元数据,永远不会有主动行为,但凡Annotation起作用的场合都是有一个执行机制/调用者通过反射获得了这个元数据然后根据它采取行动。

通过反射机制获取函数注解信息

      Method[] declaredMethods = IReqApi.class.getDeclaredMethods();
for (Method method : declaredMethods) {
Annotation[] methodAnnotations = method.getAnnotations();
Annotation[][] parameterAnnotationsArray = method.getParameterAnnotations();
}

也可以获取指定的注解

ReqType reqType =method.getAnnotation(ReqType.class);
4.)具体实现注解接口调用

这里采用Java动态代理机制来实现,将定义接口与实现分离开,这个后期有时间再做总结。

    private void testApi() {
IReqApi api = create(IReqApi.class);
api.login("whoislcj", "123456");
} public <T> T create(final Class<T> service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
new InvocationHandler() { @Override
public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {// Annotation[] methodAnnotations = method.getAnnotations();//拿到函数注解数组
ReqType reqType = method.getAnnotation(ReqType.class);
Log.e(TAG, "IReqApi---reqType->" + (reqType.reqType() == ReqType.ReqTypeEnum.POST ? "POST" : "OTHER"));
ReqUrl reqUrl = method.getAnnotation(ReqUrl.class);
Log.e(TAG, "IReqApi---reqUrl->" + reqUrl.reqUrl());
Type[] parameterTypes = method.getGenericParameterTypes();
Annotation[][] parameterAnnotationsArray = method.getParameterAnnotations();//拿到参数注解
for (int i = 0; i < parameterAnnotationsArray.length; i++) {
Annotation[] annotations = parameterAnnotationsArray[i];
if (annotations != null) {
ReqParam reqParam = (ReqParam) annotations[0];
Log.e(TAG, "reqParam---reqParam->" + reqParam.value() + "==" + args[i]);
}
}
//下面就可以执行相应的网络请求获取结果 返回结果
String result = "";//这里模拟一个结果 return result;
}
});
}

打印结果:

以上通过注解定义参数,通过动态代理方式执行函数,模拟了最基本的Retrofit 2中网络实现原理。

Java学习之注解Annotation实现原理的更多相关文章

  1. Java学习:注解,反射,动态编译

    狂神声明 : 文章均为自己的学习笔记 , 转载一定注明出处 ; 编辑不易 , 防君子不防小人~共勉 ! Java学习:注解,反射,动态编译 Annotation 注解  什么是注解 ? Annotat ...

  2. Java学习之注解篇

    Java学习之注解篇 0x00 前言 续上篇文章,这篇文章就来写一下注解的相关内容. 0x01 注解概述 Java注解(Annotation)又称Java标注,是JDK5.0约会的一种注释机制. 和J ...

  3. 0035 Java学习笔记-注解

    什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...

  4. java中的注解(Annotation)

    转载:https://segmentfault.com/a/1190000007623013 简介 注解,java中提供了一种原程序中的元素关联任何信息.任何元素的途径的途径和方法. 注解是那些插入到 ...

  5. java学习之注解

    0x00前言 1.注解是什么: (1)可以叫做注释类型,注解是一种引用数据类型,编译后也是生成class文件 (2)提供信息给编译器: 编译器可以利用注解来探测错误和警告信息 比如 @Override ...

  6. Java学习之==>注解

    一.概述 关于注解,首先引入官方文档的一句话:Java 注解用于为 Java 代码提供元数据.作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的.接下我将从注解的定义. ...

  7. 注解Annotation实现原理与自定义注解例子

    什么是注解? 对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metada ...

  8. java AOP使用注解@annotation方式实践

       java AOP使用配置项来进行注入实践 AOP实际开发工作比较常用,在此使用注解方式加深对面向切面编程的理解 废话不多少,先看下面的实例代码 场景: 1.未满一岁的小孩,在执行方法之前打印:“ ...

  9. java基础篇---注解(Annotation)

    一.概念 Annontation是Java5开始引入的新特征.中文名称一般叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类.方法.成员变量等)进行关 ...

随机推荐

  1. XStream将java对象转换为xml时,对象字段中的下划线“_”,转换后变成了两个的解决办法

            在前几天的一个项目中,由于数据库字段的命名原因 其中有两项:一项叫做"市场价格"一项叫做"商店价格" 为了便于区分,遂分别将其命名为market ...

  2. ExtJS 4.2 介绍

    本篇介绍ExtJS相关知识,是以ExtJS4.2.1版本为基础进行说明,包括:ExtJS的特点.MVC模式.4.2.1GPL版本资源的下载和说明以及4种主题的演示. 目录 1. 介绍 1.1 说明 1 ...

  3. nodejs创建http服务器

    之前有简单介绍nodejs的一篇文章(http://www.cnblogs.com/fangsmile/p/6226044.html) HTTP服务器 Node内建有一个模块,利用它可以很容易创建基本 ...

  4. 零OCR基础6行代码实现C#验证码识别

    这两天因为工作需要,要到某个网站采集信息,一是要模拟登陆,二是要破解验证码,本想用第三方付费打码,但是想想网上免费的代码也挺多的,于是乎准备从网上撸点代码下来,谁知道,撸了好多个都不行,本人以前也没接 ...

  5. 对Thoughtworks的有趣笔试题实践

    记得2014年在网上看到Thoughtworks的一道笔试题,当时觉得挺有意思,但是没动手去写.这几天又在网上看到了,于是我抽了一点时间写了下,我把程序运行的结果跟网上的答案对了一下,应该是对的,但是 ...

  6. Aaron Stannard谈Akka.NET 1.1

    Akka.NET 1.1近日发布,带来新特性和性能提升.InfoQ采访了Akka.net维护者Aaron Stannard,了解更多有关Akka.Streams和Akka.Cluster的信息.Aar ...

  7. 使用JavaScript为一张图片设置备选路径

    在做网页开发的时候,有时候希望给图片设置一个备选路径,即,当src属性对应的主路径加载失败的时候,图片可以马上切换到备选路径.这样,即使主路径失效了,显示备用路径也不会影响网页的正常体验. 注意到网页 ...

  8. JAVA设计模式之模板模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式 ...

  9. 完美解决CodeSmith无法获取MySQL表及列Description说明注释的方案

    问题描述: CodeSmith是现在比较实用的代码生成器,但是我们发现一个问题: 使用CodeSmith编写MySQL模板的时候,会发现一个问题:MySQL数据表中的列说明获取不到,也就是column ...

  10. Mysql - 函数

    Mysql提供的函数是在是太多了, 很多我都见过, 别说用了. 园子里面, 有人弄了一个比较全的. MYSQL函数 我这里会将他写的完全拷贝下来, 中间会插入一些自己项目中使用过的心得 一.数学函数 ...