前言:

最近学习了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() {@Overridepublic 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中的注解(Annotation)处理器解析

    Java中的注解(Annotation)是一个很神奇的东西,特别现在有很多Android库都是使用注解的方式来实现的.一直想详细了解一下其中的原理.很有幸阅读到一篇详细解释编写注解处理器的文章.本文的 ...

  2. Java反射自定义注解底层设计原理

    文章目录 一.反射 1. 反射概念 2. 反射机制的优缺点 3. 反射的用途 4. 反射技术的使用 5. 反射常用的Api 6. 反射执行构造函数 7. 反射执行给属性赋值 8. 反射执行调用方法 二 ...

  3. Java、Android注解代码生成(ButterKnife原理、ViewBinding)

    前言 首先需要一些先验知识: 浅谈Java/Android下的注解 Java.Android基础之-反射 Java.Android静态代理与动态代理 简介 在我们常用的框架中注解和自动生成代码的身影很 ...

  4. Java中的注解--annotation

    Java中的基本注解,几乎框架中的注解都是依赖Java中的基本注解,很有必要学习一下Java中的基本注解...jdk 5 增加的新特性 一.注解的定义以及Java中常见的注解 注解就相当于一种标记,加 ...

  5. Java学习之注解(五)Android循序渐进实现高逼格自定义ViewBinder

    前言 Butterknife的代码到目前为止还没有仔细去看,这里也是自己在网上找的一个资料,主要是针对注解学习理解,但是发现这个学习资料估计是在Butterknife里面扣的,因为如果单单实现一个Vi ...

  6. 彻底搞懂 Java 中的注解 Annotation

    Java注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分.注解对于代码的运行效果没有直接影响. 网络上对注解的解释过于严肃.刻板,这并不是我喜欢的风格.尽管这样的 ...

  7. Java学习日报—注解、Hash、Lombok—2021/12/02

    目录 1 相关注解 1.1 @Controller 和 @RestController 1.2 @ApiIgnore 1.3 @PostMapping 2 Java知识点 2.1 instanceof ...

  8. java学习小结:set集合原理及特点

    文章目录 Set集合 一.HashSet 二.LinkedHashSet 三.TreeSet 自然排序 定制排序 Set集合 Set集合是collection的另一个子接口,包括三个实现类:HashS ...

  9. java的标准注解和元注解

    目录 注解Annotation实现原理与自定义注解例子 1.什么是注解 2.注解的用处 3.注解的原理 4.元注解 5.常见标准的Annotation 6.自定义注解 7.自定义注解实例 注解Anno ...

最新文章

  1. 在centos下启动nginx出现Failed to start nginx.service:unit not found
  2. LightGBM用法速查表
  3. Java8 PriorityBlockingQueue源码分析
  4. LINUX 内存使用情况
  5. Android记录日志方式,关于Android中处理崩溃异常和记录日志的另一种实现思路
  6. 如何批量转换图片格式?怎样统一修改图片格式?
  7. Unity3D实战【一】Create Project 创建项目导入素材
  8. jq实现点击复制文本功能
  9. 一个心理医生和一个心理不正常的小孩的冷笑话
  10. 【jpa】简介和项目生成、API-初级入门
  11. 小红书用户画像分析_用户画像,该怎么分析?
  12. 无限渗透实战(2)--绕过认证上校园网
  13. 性能测试中的服务器数据监控
  14. 使用伪类来实现类似微信群聊的头像样式
  15. HTML5第十课时,会员卡号返利练习
  16. 小程序实现长按图片弹出保存图片、发送给朋友、识别图中码菜单。
  17. 计算机网络与物联网工程专业大学排名,大学专业“薪酬”排名公布,物联网工程仅排第五,有你的专业吗...
  18. 网络工程系统集成模型
  19. 雷神之锤冠军游戏角色高清Mac动态壁纸
  20. java发送pdf格式邮件_java – 以Pdf附件的形式发送电子邮件作为流

热门文章

  1. 学习vulkan的几个有用的网址
  2. Unity中那些事半功倍的好插件
  3. 日本CG大神又整活了!3D建模软件拿来搞面部实时捕捉,网友:效果好得有点吓人...
  4. 首届丘成桐女子中学生数学竞赛成绩出炉,成都七中成最大赢家,摘得1金2银1优胜...
  5. 美国版“非升即走”瞄准终身教授,2年评审不通过就减薪撤职,其他高校开始抢人...
  6. 还在担心工作被AI取代?不如掌握这门硬实力,抢占职场发展机遇
  7. Nature:首个完全复现人眼的仿生眼问世,港科大造出半球形人工视网膜,感光性能超过人眼460倍...
  8. DeeCamp 2020启动,邀请全球AI菁英共克世界变局下真实难题!
  9. JavaScript之各种继承方式和优缺点
  10. 蓝光模式引爆欧洲杯 神马搜索陪你度过激情夏日