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

对注解概念不了解的可以先看这个:Java注解基础概念总结

前面有提到注解按生命周期来划分可分为3类:

1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;

2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;

3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;

这3个生命周期分别对应于:Java源文件(.java文件) ---> .class文件 ---> 内存中的字节码。

那怎么来选择合适的注解生命周期呢?

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override
和 @SuppressWarnings,则可选用 SOURCE 注解。

下面来介绍下运行时注解的简单运用。

获取注解

你需要通过反射来获取运行时注解,可以从 Package、Class、Field、Method...上面获取,基本方法都一样,几个常见的方法如下:

[java] view plain copy

  1. /**
  2. * 获取指定类型的注解
  3. */
  4. public <A extends Annotation> A getAnnotation(Class<A> annotationType);
  5. /**
  6. * 获取所有注解,如果有的话
  7. */
  8. public Annotation[] getAnnotations();
  9. /**
  10. * 获取所有注解,忽略继承的注解
  11. */
  12. public Annotation[] getDeclaredAnnotations();
  13. /**
  14. * 指定注解是否存在该元素上,如果有则返回true,否则false
  15. */
  16. public boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
  17. /**
  18. * 获取Method中参数的所有注解
  19. */
  20. public Annotation[][] getParameterAnnotations();

要使用这些函数必须先通过反射获取到对应的元素:Class、Field、Method 等。

自定义注解

来看下自定义注解的简单使用方式,这里先定义3个运行时注解:

[java] view plain copy

  1. // 适用类、接口(包括注解类型)或枚举
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target(ElementType.TYPE)
  4. public @interface ClassInfo {
  5. String value();
  6. }
  7. // 适用field属性,也包括enum常量
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Target(ElementType.FIELD)
  10. public @interface FieldInfo {
  11. int[] value();
  12. }
  13. // 适用方法
  14. @Retention(RetentionPolicy.RUNTIME)
  15. @Target(ElementType.METHOD)
  16. public @interface MethodInfo {
  17. String name() default "long";
  18. String data();
  19. int age() default 27;
  20. }

这3个注解分别适用于不同的元素,并都带有不同的属性,在使用注解是需要设置这些属性值。

再定义一个测试类来使用这些注解:

[java] view plain copy

  1. /**
  2. * 测试运行时注解
  3. */
  4. @ClassInfo("Test Class")
  5. public class TestRuntimeAnnotation {
  6. @FieldInfo(value = {1, 2})
  7. public String fieldInfo = "FiledInfo";
  8. @FieldInfo(value = {10086})
  9. public int i = 100;
  10. @MethodInfo(name = "BlueBird", data = "Big")
  11. public static String getMethodInfo() {
  12. return TestRuntimeAnnotation.class.getSimpleName();
  13. }
  14. }

使用还是很简单的,最后来看怎么在代码中获取注解信息:

[java] view plain copy

  1. /**
  2. * 测试运行时注解
  3. */
  4. private void _testRuntimeAnnotation() {
  5. StringBuffer sb = new StringBuffer();
  6. Class<?> cls = TestRuntimeAnnotation.class;
  7. Constructor<?>[] constructors = cls.getConstructors();
  8. // 获取指定类型的注解
  9. sb.append("Class注解:").append("\n");
  10. ClassInfo classInfo = cls.getAnnotation(ClassInfo.class);
  11. if (classInfo != null) {
  12. sb.append(Modifier.toString(cls.getModifiers())).append(" ")
  13. .append(cls.getSimpleName()).append("\n");
  14. sb.append("注解值: ").append(classInfo.value()).append("\n\n");
  15. }
  16. sb.append("Field注解:").append("\n");
  17. Field[] fields = cls.getDeclaredFields();
  18. for (Field field : fields) {
  19. FieldInfo fieldInfo = field.getAnnotation(FieldInfo.class);
  20. if (fieldInfo != null) {
  21. sb.append(Modifier.toString(field.getModifiers())).append(" ")
  22. .append(field.getType().getSimpleName()).append(" ")
  23. .append(field.getName()).append("\n");
  24. sb.append("注解值: ").append(Arrays.toString(fieldInfo.value())).append("\n\n");
  25. }
  26. }
  27. sb.append("Method注解:").append("\n");
  28. Method[] methods = cls.getDeclaredMethods();
  29. for (Method method : methods) {
  30. MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
  31. if (methodInfo != null) {
  32. sb.append(Modifier.toString(method.getModifiers())).append(" ")
  33. .append(method.getReturnType().getSimpleName()).append(" ")
  34. .append(method.getName()).append("\n");
  35. sb.append("注解值: ").append("\n");
  36. sb.append("name: ").append(methodInfo.name()).append("\n");
  37. sb.append("data: ").append(methodInfo.data()).append("\n");
  38. sb.append("age: ").append(methodInfo.age()).append("\n");
  39. }
  40. }
  41. System.out.print(sb.toString());
  42. }

所做的操作都是通过反射获取对应元素,再获取元素上面的注解,最后得到注解的属性值。

看一下输出情况,这里我直接显示在手机上:

这个自定义运行时注解是很简单的例子,有很多优秀的开源项目都有使用运行时注解来处理问题,有兴趣可以找一些来研究。因为涉及到反射,所以运行时注解的效率多少会受到影响,现在很多的开源项目使用的是编译时注解,关于编译时注解后面再来详细介绍。

时间: 2024-12-25 14:28:57

自定义注解之运行时注解(RetentionPolicy.RUNTIME)的相关文章

Android运行时注解

Android的注解有编译时注解和运行时注解,本文就介绍下运行时注解. 其实非常简单,直接上代码:本文主要是替代传统的findViewById()的功能,就是在我们Activity中不需要再使用findViewById()去给View赋值了,通过注解在运行阶段自动赋值.以及setOnClickListener()也是一样的原理.使用注解和反射技术. 1. 定义自己的annotation注解. 定义findViewbyId这个功能的注解 package com.xxx.xxx.xxx; impor

android N 7.0之运行时注解|Mexicande

must be regedit "" in activity or this activity have annotation 最近在做一个新的项目的时候使用了一个别人的库,只是为了偷懒少敲一些代码,期限在测试一直没问题,但是在android 7.0上面测试,虽然提示must be regedit "" in activity or this activity have annotation 字面意思是,""库需要去注册或者这个activity使

[转帖]运行时库(runtime library)

运行时库(runtime library) https://blog.csdn.net/xitie8523/article/details/82712105 没学过这些东西 或者当时上课没听 又或者 世一大的老师没好好讲 只顾着开公司赚钱了. 2018年09月15日 11:34:33 xisuesuexi 阅读数 593 一切从   默认库“LIBCMTD”与其他库的使用冲突,请使用 /NODEFAULTLIB:library. error LNK2005: XXX已经在 libcmtd.lib

ILBC 运行时 (ILBC Runtime) 架构

本文是 VMBC / D# 项目 的 系列文章, 有关 VMBC / D# , 见 <我发起并创立了一个 VMBC 的 子项目 D#>(以下简称 <D#>)  https://www.cnblogs.com/KSongKing/p/10348190.html   . ILBC 运行时       架构图    如下: 为了便于讲解,   图中 一些位置 标注了 红色数字 . ILBC 运行时  包含  3 个 部分:   调度程序 . C 编译器 . GC  . 1 处,  调度程

JAVA自定义注解 和 运行时靠 反射获取注解,解决 shiro 注解型权限因子获取问题

项目的权限分配,采用的是RBAC的设计模式.后台配置权限的时候,需要获取到所有的权限因子. 不经让我想起YII框架的SRBAC模块,还有以前的一个ecshop改造系统的权限配置方式,都采用的是PHP的反射机制. 于是把PHP项目的经验带到JAVA项目中,发现PHP中的经验在java中,实现起来不是那么的方便. 这主要的原因:一是语言上的特性导致权限控制方面的差异性. 二是项目使用的是SSH框架,action的名称已经使用注解替换了原有名称.使用反射获取到的类名和方法名组合,不是有效的权限因子(当

ABAP运行时类型服务 Runtime Type Services (RTTS)

RTTS (RunTime Type Services)允许获得变量的定义,或者在程序运行期间创建它们.RTTS由2个组件组成: RTTI(RunTime Type Identification)用于获取已存在类型或已存在变量的定义. RTTC(RunTime Type Creation)用于使用定义创建新的变量:需要创建的变量必须通过ABAP语句CREATE DATA ... TYPE HANDLE创建. RTTI和RTTC可以通过使用类CL_ABAP_*DESCR中的方法访问.每个类都有RT

HappyBKs教你写Java注解(1)——注解的分类、运行机制、作用域及概念汇总

注解这东西,已经在我们的编程生活中习以为常了.覆盖一个父类的方法,套用Spring.Mybatis中的编程套路,编写JUnit测试函数等等.你会发现,作为一个Java Coder,你无时无刻不在接触它们. 但是如何编写一个属于自己的注解,或是希望能够看懂那些NB框架的源代码,都有必要让你我去掌握编写自定义注解的方法. 本系列开始,我将和博客的观众们一起学习java注解的开发. 注解分类(按照来源来分) jdk中的注解: @Override 重写父类的方法.如果父类没有该方法则编译报错 @Over

关于java编译时注解你需要知道的二三事。解除你的顾虑!

转载请注明出处: http://blog.csdn.net/liu470368500/article/details/51316066 做Android开发.大家肯定会关心你的app的性能问题.不知道从何时开始.网上有流传一句.不要使用注解.用注解会影响性能.这不能说错.但是也不能说对.这里普及一下关于注解的一些你需要知道的知识 网上常说的注解.基本是运行时注解.而所说的注解会影响性能.则是指的此类型的注解.因为运行时注解的解析.完全依赖于反射.而反射的效率.是比原生的慢的.特别是对于原先的老机

Android 编译时注解-提升

Android 编译时注解-提升 背景 在前面的文章中,讲解了注解和编译时注解等一些列相关的内容,为了更加全面和真是的了解Android 编译时注解在实战项目中的使用,本文采取实现主流框架butterknife注入view去全面认识编译时注解. 注解专栏-博客 效果 先来张图压压惊,实现效果butterknife的view绑定 使用 仿照butterknife实现了@BindView注解,通过WzgJector.bind方法绑定当前MainActivity,整体和butterknife使用完全一