(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~
保留在源码级别注解的应用场景
1.注解的应用场景
(1)根据注解的保留级别不同,对注解的使用自然存在不同场景。
(2)由注解的三个不同保留级别可知,注解作用于:源码、字节码与运行时时你能举一些案例吗?
级别 | 技术 | 说明 |
---|---|---|
源码 | APT | 在编译期能够获取注解声明的类,包括类中的所有成员信息,一般用于生成额外的辅助类。 |
字节码 | 字节码增强 | 在编译出class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解 |
运行时 | 反射 | 在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判定。 |
2.保留在源码SOURCE级别注解的应用场景
主要是结合APT(Annotation Processor Tools)技术,在编译期获取注解声明的类,以及类中的所有成员信息,常用于生成辅助类。
2.1APT注解处理器
APT:Annotation Processor Tools (注解处理工具)
2.1.1注解处理器是如何运行的,运行在什么阶段的?
(1).java - > javac —> .class
(2).java文件需要 通过javac 编译成class文件
(3)采集所有的注解信息
(4)将采集的信息包装成元素节点Element
(5)由javac去调起注解处理器,执行我们的注解处理程序。(不是我们手动调用的,是由javac去调用的)
(6)注解处理程序是在类文件被javac编译成字节码文件之前执行的。
2.1.2 注解处理器定义
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;
public class LanceProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}
}
(1)让我们的类extends AbstractProcessor,这一个类就是一个注解处理程序。
(2)这一个类会被javac在编译的时候去实例化,然后再调用里面的process方法.
(3)写好这样一个类之后,javac还是不能直接去调用它,即仍然不能使用它,还缺少很关键的一步,还需要去注册。
2.1.3如何注册注解处理器?
(1)在main目录下面创建一个名为resources的目录
(2)在resources目录之下再创建一个名为META-INF,(注意不要把INF写成INFO)
(3)在META-INF目录下再创建services目录
(4)在services目录之下创建javax.annotation.processing.Processor文件
(5)在文件中写入注解处理程序的全类名
com.gdc.compiler.LanceProcessor
(6)注解处理程序编写
-
在注解处理器的实现方法里面,输出一些信息
-
不要使用System.out.pringln去输出,用processingEnv这个成员属性去输出.
-
注解处理程序是否可以指定处理某个注解呢?
可以通过@SupportedAnnotationTypes注解指定注解处理器只处理某个注解。
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
@SupportedAnnotationTypes("com.gdc.javabase.annotation.Lance")
public class LanceProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//s1.获取messager对象
Messager messager = processingEnv.getMessager();
//s2.设置输出消息级别
messager.printMessage(Diagnostic.Kind.NOTE,"=======注解处理器程序被调用=======");
return false;
}
}
(7)在app模块中去引用注解处理器模块,即修改build.gradle文件
//s1.引用注解处理器程序模块
annotationProcessor project(':compiler')
(8)编译项目,查看注解处理程序运行结果
- Build ----> make project
- 结果如下图所示:
2.1.4 使用Google插件注册注解处理器
(1)Google提供了一个插件来帮助我们更方便的注册注解处理器,你只需要导入对应的依赖包,在自定义的Processor类上方添加@AutoService(Processor.class)即可。
(2)导入依赖包
api 'com.google.auto.service:auto-service:1.0-rc2'
(3)添加声明
@AutoService(Processor.class)
@SupportedAnnotationTypes("com.gdc.annotationprocessor.annotation.Address")
public class AddressProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//s1.获取messager对象
Messager messager = processingEnv.getMessager();
//s2.设置消息级别
messager.printMessage(Diagnostic.Kind.NOTE,"=======注解处理器程序被调用=======");
return false;
}
}
(4)这种方式存在AutoService与gradle版本不兼容的问题,导致注解处理器无法获得执行,通常会采用gradle降级的方式处理,所以不太可取,后期看是事会有更优的方案处理这个兼容的问题。
解决方法:https://blog.csdn.net/qq_39969226/article/details/104538438
2.2使用注解制定IDE语法检查规则
2.2.1@IntDef注解
(1)在Android开发中,support-annotations与androidx.annotation中均有提供@InDef注解,此注解的定义如下:
@Retention(SOURCE)
@Target({ANNOTATION_TYPE})
public @interface IntDef {
int[] value() default {};
boolean flag() default false;
boolean open() default false;
}
(2)Java中Enum(枚举)的实质是特殊的静态成员变量,在运行期所有枚举类作为单例,全部加载到内存中。比常量多5到10倍的内存占用。
(3)此注解的意义在于能够取代枚举,实现如方法参数限制。
(4)@IntDef是一个元注解。
(5)利用注解检测语法规则案例
class Test2 {
//s1.此处的@DrawableRes注解是提供一个语法检查的
public static void setDrawable(@DrawableRes int id){
}
public static void main(String[] args) {
//s1.@DrawableRes注解的应用,限定只能传递drawable型的整型资源数据
setDrawable(R.drawable.ic_launcher_background);
}
}
2.2.2使用@IntDef注解来制定我们自己的语法检测规则
2.2.2.1使用枚举的缺点
-
在Java中,枚举本质上是对象,比较占用内存。
-
一个对象占用几个字节?是由12个字节的对象头,加上它的成员所占的字节构成的,同时还有8个字节的对齐。
-
枚举比较占用内存,可以考虑使用常量代替枚举类型来降低对内存的占用。
2.2.2.2枚举的应用举例
class Test {
private static WeekDay mCurrentDay;
enum WeekDay{
SUNDAY,MONDAY
}
public static void setCurrentDay(WeekDay weekDay){
mCurrentDay = weekDay;
}
public static void main(String[] args) {
//s1.枚举的应用
setCurrentDay(WeekDay.SUNDAY);
}
}
2.2.2.3使用自定义注解限定方法的入参参数值的选定范围
使用常量代替枚举类型来降低对内存的占用
public class Test3 {
private static final int SUNDAY = 0;
private static final int MONDAY = 1;
@WekDay
private static int mCurrentIntDay;
//s1.定义一个注解,实现方法参数的限定
@IntDef({SUNDAY,MONDAY})//限定入参参数值的选定范围
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.SOURCE)
@interface WekDay{
}
//s2.使用@IntDef注解来制定我们自己的语法检测规则,对int型的入参数据做一些限定
public static void setCurrentDay(@WekDay int currentDay){
mCurrentIntDay = currentDay;
}
public static void main(String[] args) {
//s3.@IntDef注解的应用
setCurrentDay(SUNDAY);
}
}
2.2.2.4注解实现语法检查是由谁做的?
(1)由IDE实现的,或者说是由IDE插件实现的。
(2)IDEA是由Java开发的,它可以对我们的文件进行分析,对我们的语法进行检测。
3.打赏鼓励
感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!