注解和注解生成器

如果没有处理注解的工具,那么注解也不会有太大的作用。对于不同的注解有不同的注解处理器。虽然注解处理器的编写千变万化,但是也有处理标准。
参考文献:https://blog.csdn.net/jdfkldjlkjdl/article/details/110937447?utm_term=java%E6%B3%A8%E8%A7%A3%E5%A4%84%E7%90%86%E5%99%A8%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduweb~default-2-110937447&spm=3001.4430
参考文献:https://blog.csdn.net/yamadeee/article/details/96479009

1.反射基本知识

类和类加载器:Java虚拟机是通过类加载器将类信息加载到Java虚拟机中的。

a.类信息中包含类中的所有信息,可以通过反射拿到类中所有的信息。
//待反射拿到的类
public class ReflectDemo {public String name;private int age;public ReflectDemo(String name, int age) {this.name = name;this.age = age;}private ReflectDemo() {}public String getName() {return name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return showString();}private String showString() {return "Demo{" +"name='" + name + '\'' +", age=" + age +'}';}
}

反射操作:

public class Demo {public static void main(String[] args) {//1.获取类中声明的构造函数,私有&公开Constructor<?>[] declaredConstructors = ReflectDemo.class.getDeclaredConstructors();for (Constructor<?> constructor : declaredConstructors) {show("declaredConstructors", constructor);}//2.获取类中公开构造函数Constructor<?>[] constructors = ReflectDemo.class.getConstructors();for (Constructor<?> constructor : constructors) {show("constructor", constructor);}//3.获取类中所有声明的函数,私有&公开Field[] declaredFields = ReflectDemo.class.getDeclaredFields();for (Field declaredField : declaredFields) {show("declaredField", declaredField);}//4.获取类中所有的共有函数,包括继承的Field[] fields = ReflectDemo.class.getFields();for (Field field : fields) {show("field", field);}Method[] declaredMethods = ReflectDemo.class.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {show("declaredMethod", declaredMethod);}Method[] methods = ReflectDemo.class.getMethods();for (Method method : methods) {show("method", method);}}private static void show(String tag, Object object)  {System.out.println(String.format("Demo tag : %s output : %s", tag, object.toString()));}
}
b.调用类中的方法
//反射调用对象中的toString方法
public class Demo {public static void main(String[] args) {try {ReflectDemo reflectDemo = new ReflectDemo("JC", 23);//1.通过反射调用对象的toString方法Method toString = ReflectDemo.class.getMethod("toString");show("toString", toString);String ret = (String) toString.invoke(reflectDemo);show("ret", ret);//2.通过反射调用对象的fieldField name = ReflectDemo.class.getField("name");String nameField = (String) name.get(reflectDemo);show("nameField", nameField);//3.通过反射调用构造函数Constructor<ReflectDemo> constructor = ReflectDemo.class.getConstructor(String.class, int.class);ReflectDemo reflectDemoConstructed = constructor.newInstance("luogou", 24);show("constructor", reflectDemoConstructed.toString());} catch (Exception e) {e.printStackTrace();}}private static void show(String tag, Object object)  {System.out.println(String.format("Demo tag : %s output : %s", tag, object.toString()));}
}

2.反射拿到注解信息

注解根据Retention属性,可表明是保留在source、class还是runtime三个阶段。

//注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FirstAnno {String name();int age();String time();
}//注解的使用
@FirstAnno(name = "JC", age = 27,time = "2021-8-7")
public class FirstClass {}

由于,注解信息只在源码阶段存在,所以查看编译的字节码如下:

//1.保留策略为源码,所以编译的字节码没有注解信息了
public class FirstClass {public FirstClass() {}
}//2.保留策略为class类,字节码就会有注解信息。但是注意,在运行期(代码中反射)是无法获取到的!!!字节码文件如下:
@FirstAnno(name = "JC",age = 27,time = "2021-8-7"
)
public class FirstClass {public FirstClass() {}
}//3.保留策略为runtime类,字节码会有注解信息,并且还是可以在运行期获取到。字节码为文件同保留策略为class时候。public class Demo {public static void main(String[] args) {Annotation[] annotations = FirstClass.class.getAnnotations();for (Annotation annotation : annotations) {show("annotation", annotation);}Annotation[] declaredAnnotations = FirstClass.class.getDeclaredAnnotations();for (Annotation declaredAnnotation : declaredAnnotations) {show("declaredAnnotation", declaredAnnotation);}FirstAnno[] annotationsByTypes = FirstClass.class.getAnnotationsByType(FirstAnno.class);for (FirstAnno annotationsByType : annotationsByTypes) {show("annotationsByType", annotationsByType);}FirstAnno[] declaredAnnotationsByTypes = FirstClass.class.getDeclaredAnnotationsByType(FirstAnno.class);for (FirstAnno declaredAnnotationsByType : declaredAnnotationsByTypes) {show("declaredAnnotationsByType", declaredAnnotationsByType);}}private static void show(String tag, Object object)  {System.out.println(String.format("Demo tag : %s output : %s", tag, object.toString()));}
}

3.三种保留策略的补充说明

  • 如果保留策略为source,那么注解信息只会保存在.java源文件中;
  • 如果保留策略为class,那么注解信息只会保存在.java源文件和.class字节码文件中;
  • 如果保留策略为runtime,那么注解信息会保存在.java源文件、.class字节码文件和在类加载后。注意,类加载后保留了注解信息,那么就可以在代码中通过反射拿到相应的注解信息了!

通常有两种,一是编译时注解处理器,一是运行时注解处理器。上面“2.反射拿到注解信息”其实就是一种运行时注解处理器的实现了。而编译时注解处理器,在工程编译过程中对注解进行处理,也就是执行操作的期间只在编译期间内,这会在“6.Android Studio中的注解处理器”中进行举例。

4.获取泛型参数

@FirstAnno(name = "JC", age = 27,time = "2021-8-7")
public class FirstClass<T, R> {T name;R info;
}public class Demo {public static void main(String[] args) {FirstClass<Integer, String> demo = new FirstClass<>();TypeVariable<? extends Class<? extends FirstClass>>[] typeParameters = demo.getClass().getTypeParameters();for (TypeVariable<? extends Class<? extends FirstClass>> typeParameter : typeParameters) {show("typeParameter", typeParameter);}}private static void show(String tag, Object object)  {System.out.println(String.format("Demo tag : %s output : %s", tag, object.toString()));}
}

5.注解处理器

如果没有处理注解的工具,那么注解也只会在source、class或者runtime的代码中增加部分信息,是不会有太大的作用。想要注解生效,就需要针对这些信息进行解析的。

自定义注解处理器,其实就是反射获取注解的属性,例如运行时注解的获取在类型2中已经展示了。其实,Java中有更好的方式,通过继承实现AbstractProcessor即可。

@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("com.example.processors.DemoAnno")
public class CustomProcessor extends AbstractProcessor {@Overridepublic boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {Messager messager = processingEnv.getMessager();for (Element ele : roundEnvironment.getElementsAnnotatedWith(DemoAnno.class)) {messager.printMessage(Diagnostic.Kind.NOTE, "printMessage:" + ele.toString() + ", kind: " + ele.getKind());// 获取注解的元数据DemoAnno annotation = ele.getAnnotation(DemoAnno.class);String annoInfo = String.format("annotation class: %s, value: %d, name: %s", annotation.getClass(), annotation.value(), annotation.name());messager.printMessage(Diagnostic.Kind.NOTE, annoInfo);}return true;}@Overridepublic synchronized void init(ProcessingEnvironment processingEnvironment) {super.init(processingEnvironment);}@Overridepublic Set<String> getSupportedAnnotationTypes() {Set<String> annotations = new LinkedHashSet<>();annotations.add(DemoAnno.class.getCanonicalName());return annotations;}@Overridepublic SourceVersion getSupportedSourceVersion() {return SourceVersion.latestSupported();}
}

6.Android Studio中的注解处理器

在Android Studio中使用自定义注解处理器的方法,是无法通过继承实现AbstractProcessor的,这个在Android app或者library模块中都是无法使用的,Android中应该是有更加好的方式实现注解处理器功能的(可能是apt依赖的使用,后续研究补充)。
所以,想要在Android Studio中使用JDK自带的AbstractProcessor方式,那么就只能够在Android中创建Java或者Kotlin原生库,然后在内部实现相应功能,再被上层Android的app或者library模块使用。注意:Java原生库也无法通过依赖,然后使用Android的app或者library模块。
所以,通过在Android Studio中“File-New-New Module-Java or Kotlin Library”,创建原生的Java库。

项目结构如下所示,annotation和processors模块都是原生Java模块,而app就是Android的模块。

  • annotation模块是一个Java库,定义了各种注解内容,以底层api工具包被外部依赖。内容如下:
java
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface DemoAnno {int value();String name();
}
  • processors模块也是一个Java库,定义了各种注解处理器,被外部以注解处理器方式依赖。内容见“5.注解处理器”。另外,gradle文件需要依赖annotation模块:
dependencies {implementation project(':annotation')// auto serviceimplementation 'com.google.auto.service:auto-service:1.0-rc6'annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
}
  • app模块,直接使用了processors模块,并以来annotation模块,其gradle文件如下:
dependencies {//依赖注解接口模块implementation project(path: ':annotation')//使用注解处理器annotationProcessor project(':processors')
}
//MainActivity.java
@DemoAnno(value = 123, name = "JC")
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}//MyService.java
@DemoAnno(value = 666, name = "GoGoGO")
public class MyService extends Service {public MyService() {}@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException("Not yet implemented");}
}

那么编译项目的时候便会在“build”窗口中看到如下日志输出:

.......
> Task :app:compileDebugJavaWithJavac
The following annotation processors are not incremental: processors.jar (project :processors).
Make sure all annotation processors are incremental to improve your build speed.
注: printMessage:com.example.annotationdemo.MainActivity, kind: CLASS
注: annotation class: class com.sun.proxy.$Proxy197, value: 123, name: JC
注: printMessage:com.example.annotationdemo.MyService, kind: CLASS
注: annotation class: class com.sun.proxy.$Proxy197, value: 666, name: GoGoGO
.......
BUILD SUCCESSFUL in 4s
31 actionable tasks: 31 executedBuild Analyzer results available

Android中自定义注解处理器相关推荐

  1. Android 自定义注解处理器详解

    文章目录 AbstractProcessor 方法详细信息 ProcessingEnvironment 方法详细信息 1 新建 Java Library 1.1 新建 1.2 确定依赖关系 2 创建自 ...

  2. 注解提高篇:自定义注解处理器(APT)

    ## 0x01 继承AbstractProcessor抽象类 当定义好Annotation注解后,接下来就需要一个注解处理器来处理我们的自定义注解了.实现Java Annotation一般需要继承Ab ...

  3. 【Android APT】注解处理器 ( 根据注解生成 Java 代码 )

    文章目录 一.生成 Java 代码 二.实现 IButterKnife 接口 三.视图绑定主要操作 四.完整注解处理器代码 五.博客资源 Android APT 学习进阶路径 : 推荐按照顺序阅读 , ...

  4. 【Android APT】注解处理器 ( Element 注解节点相关操作 )

    文章目录 一.获取被 注解 标注的节点 二.Element 注解节点类型 三.VariableElement 注解节点相关操作 四.注解处理器 完整代码示例 五.博客资源 Android APT 学习 ...

  5. 【Android APT】注解处理器 ( 配置注解依赖、支持的注解类型、Java 版本支持 )

    文章目录 一.注解处理器 依赖 编译时注解 二.设置 注解处理器 支持的注解类型 三.设置 注解处理器 支持的 Java 版本 四.博客资源 Android APT 学习进阶路径 : 推荐按照顺序阅读 ...

  6. java自定义注解处理器_Android自定义注解处理器

    前言 在android开发中有很多运用到注解处理器(annotation processing)的框架,如常见的Butterknife,Dagger2,EventBus等,运用这些注解处理器框架大大简 ...

  7. 【Android APT】注解处理器 ( 注解标注 与 初始化方法 )

    文章目录 一.注解处理器 AbstractProcessor 二.使用注解 @AutoService(Processor.class) 标注 注解处理器 三.注解处理器 init 初始化方法 四.注解 ...

  8. Java和Android中的注解

    转载自  Java和Android中的注解 1.引言 从JDK1.5开始,引入了注解类Annotation,Annotation其实是一种接口,可以作用于类.方法.属性等等 ,它可以通过反射机制来访问 ...

  9. Java中自定义注解的使用

    Java中自定义注解的使用 一般来说,市面上有一些的框架,企业都不会直接拿过来就用,通过会做二次开发或封装,为了更加适配自己的开发规范和业务.那么在封装或适配的过程中,自定义注解就起着比较重要的作用. ...

最新文章

  1. java取网页数据_浅析JAVA实现网页取内容
  2. 编程之美-计算字符串的相似度方法整理
  3. TabHost 和 FragmentTabHost
  4. Python教程:内置函数filter()和匿名函数lambda解析
  5. MySQL如何发型不乱的应对半年数十TB数据增量
  6. Oracle发布Java 8
  7. 明晚直播预告丨Oracle 19c X86下移经验分享
  8. Python 最抢手、Java 最流行、Go 最有前途,7000 位程序员揭秘 2019 软件开发现状...
  9. 在nodeJs的Express框架下用TypeScript编写router路由出现import关键字错误的解决方案
  10. pythonrequests查询_Python Requests实例,查询成绩
  11. bugku 杂项 流量分析(cnss)
  12. 台达a2_台达伺服ASDA-A2系列解决五轴CNC方案助力雕刻机行业换代升级
  13. python rgb565_读取RGB565格式的图像
  14. php根据两点经纬度计算距离
  15. java gmail邮箱_Java - 谷歌邮箱发送邮件详解
  16. 机器学习(三):一文读懂线性判别分析(LDA)
  17. SpringMVC个人零碎总结
  18. 激活mathtype
  19. 如何用钢笔工具抠图ps教程ps学习
  20. iOS开发:分辨率像素你知多少

热门文章

  1. vue中平滑地回到顶部,回到底部
  2. 【转】珍藏多年的素材,灵感搜寻网站
  3. html背景图片动效,css3实现点击切换背景图片,并且背景图片实现动画效果
  4. 基于SPR-Fano共振的光纤传感器研究
  5. 一般的度量空间上开集的构造
  6. 计算机因特尔网络论文,[心得]英特尔
  7. 一名优秀的数据分析师,应该具备哪些基本素质?
  8. 跨越“数字鸿沟”,日本老年智能化服务的解法
  9. 创业者李一男:过去的荣耀早已归零
  10. rgb html转换,RGB与十六进制数值互转(html)