Java--注解
2023-04-18 12:33:39 时间
注解是设计框架时常用的工具,使用注解简洁明了,很多第三方框架都使用了它,如:Retrofit、EventBus等。注解的原理是编译期改变字节码,以配合APT来达到自动生成代码的目的
一、元注解
1.使用注解需要用到元注解,来指定注解的信息,一共有5个,主要使用的是下面两个:
- @Target:指定注解的作用域,类、属性、方法、构造方法等
下面表示注解作用在Class类上:
@Target(ElementType.TYPE)
public @interface Test {
}
- @Retention:注解信息维持级别,是否保存在字节码中
下面使用CLASS级别,表示编译时,保留注解信息到字节码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Test {
}
@Retention还能指定两种,一种SOURCE级别,只在源码中,不维持至字节码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Test {
}
还有一种是RUNTIME级别:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
}
CLASS在字节码中的标记为 RuntimeInvisibleAnnotations,JVM不会加载它 RUNTIME在字节码中的标记为 RuntimeVisibleAnnotations,JVM会加载,所以可以通过反射获取 SOURCE 字节码中没有注解信息,使用此注解,类似于注释
一般都是使用RUNTIME级别
2.另外三种基本不会使用:
- @Documented:使用javadoc生成API帮助文档时显示注解
- @Inherited:子类会继承父类注解
- @Repeatable:在一个地方可以多次使用注解
二、使用注解
定义一个注解,并需要实现一个方法:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
int value();
}
在类中使用,需要传入value的值,可以通过反射获取:
@Test(100)
public class TestAnnotation {
public static void main(String[] args) {
Class<TestAnnotation> testAnnotationClz = TestAnnotation.class;
Test annotation = testAnnotationClz.getAnnotation(Test.class);
int value = annotation.value();
System.out.println(value);
}
}
还可以在方法后面,使用default关键字设置默认值:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
int value() default 10;
}
三、使用APT
APT全名为Annotation Processor Tools,注解编译工具,使用它可以通过获取注解信息来自动生成相应的代码
1.创建注解Module
Module类型选择"Java or Kotlin Library",创建一个注解:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
String value() default "";
}
2.创建Processor Module
同样是"Java or Kotlin Library",gradle配置修改如下:
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies {
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
//依赖注解module
implementation project(path: ':lib_annotation')
}
创建Processor继承至AbstractProcessor,并实现方法:
@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.aruba.lib_annotation.TestAnnotation"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class TestProcessor extends AbstractProcessor {
private Messager messager;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
//获取messager
messager = processingEnv.getMessager();
messager.printMessage(Diagnostic.Kind.NOTE, "init");
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
messager.printMessage(Diagnostic.Kind.NOTE, "process");
//获取所有使用TestAnnotation注解的元素集合
Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(TestAnnotation.class);
for (Element element : elementsAnnotatedWith) {
messager.printMessage(Diagnostic.Kind.NOTE, element.getSimpleName());
}
return true;
}
}
在主Module并添加依赖:
dependencies {
implementation project(path: ':lib_annotation')
annotationProcessor project(':lib_complier')
}
使用注解:
class Main {
@TestAnnotation
String test;
public static void main(String[] args) {
}
}
编译时,就可以看到打印信息了:
相关文章
- C#并发编程-4 同步
- C#并发编程-3 并行编程基础
- StringBuilder对象和String对象相比有什么优点
- C#并发编程-2 异步编程基础-Task
- C#并发编程-1 并发编程概述
- 工具箱之 IKVM.NET 项目新进展
- C#和Java,究竟选哪个方向?我只说事实,你自己分析……
- 【Kotlin】函数式编程 ② ( 过滤函数 | predicate 谓词函数 | filter 过滤函数 | 合并函数 | zip 函数 | folder 函数 | 函数式编程意义 )
- Java生成微信小程序二维码,5种实现方式,一个比一个简单
- 【Kotlin】Kotlin 与 Java 互操作 ① ( 变量可空性 | Kotlin 类型映射 | Kotlin 访问私有属性 | Java 调用 Kotlin 函数 )
- Kotlin实现网络图片下载和保存
- 【Kotlin】Kotlin 与 Java 互操作 ③ ( Kotlin 中处理 Java 异常 | Java 中处理 Kotlin 异常 | @Throws 注解处理异常 | 函数类型互相操作 )
- Kotlin实现简单音乐播放器
- 【Kotlin】函数式编程 ① ( 函数式编程简介 | 高阶函数 | 函数类别 | Transform 变换函数 | 过滤函数 | 合并函数 | map 变换函数 | flatMap 变换函数 )
- Kotlin实现简单的学生信息管理系统
- 超详细的Java安装教程(Mac 版)
- 【历史上的今天】2 月 15 日:Pascal 之父出生;YouTube 成立;Kotlin 语言问世
- 一站式JDK安装与配置(Windows、MacOS(arm64与inter)、Linux)
- Mac系统下java环境配置
- Mac OS安装IDEA和JDK(超级详细教程)