作者:九年义务教育漏网\链接:https://juejin.cn/post/684490...相信大家在项目中用过Lombok,因为它可以简化我们很多的代码,但是有很多功能是应该有的。那么龙目岛是什么?Lombok是一个工具,可以通过简单的注解帮助我们简化和剔除一些必要但又臃肿的Java代码。简单的说,比如我们新建一个类,然后在里面写几个字段,然后通常我们需要自己手动创建getter和setter方法,构造函数等等,lombok的作用就是省去我们不用免去手动创建这些代码的麻烦,它可以在我们编译源代码的时候自动为我们生成这些方法。那么Lombok究竟是如何做到这一点的呢?实际上,底层使用了编译时注解的功能。如何使用LombokLombok是一个开源项目,代码在lombok中。如果是gradle项目,可以直接在项目中引用如下。compile("org.projectlombok:lombok:1.16.6")function那么Lombok是做什么的呢?其实很简单。一个最简单的例子就是可以通过添加注解的方式自动生成一些方法,让我们的代码更加简洁易懂。例如下面的类。@Datapublic类TestLombok{私有字符串名称;私人整数年龄;publicstaticvoidmain(String[]args){TestLomboktestLombok=newTestLombok();testLombok.setAge(12);testLombok.setName("zs");我们使用的是Lombok提供的Data注解,我们也可以不用写get和set方法,直接使用它的get和set方法。我们查看它编译好的class文件,可以看到它自动为我们生成了get和set方法。公共类TestLombok{私有字符串名称;私人整数年龄;publicstaticvoidmain(String[]args){TestLomboktestLombok=newTestLombok();testLombok.setAge(12);testLombok.setName("zs");(){}publicStringgetName(){返回this.name;}publicIntegergetAge(){returnthis.age;}publicvoidsetName(Stringname){this.name=name;}publicvoidsetAge(Integerage){this.age=age;}}当然,Lombok不止于此。还有很多其他的注解可以帮助我们轻松开发。Lombok的使用方法网上有很多,这里不再赘述。一般情况下,我们在项目中自定义注解,或者使用Spring框架中的@Controller、@Service等注解,都是运行时注解,而大多数运行时注解都是通过反射实现的。而Lombok是使用编译时注解实现的。那么什么是编译时注解呢?编译时注释注释(也称为元数据)为我们在代码中添加信息提供了一种正式的方式,以便我们可以在以后非常方便地使用这些数据。——————摘自《Thinking in Java》Java注解分为运行时注解和编译时注解。运行时注解是我们经常使用的信息,在程序运行时通过反射获取我们的注解,然后进行一些操作。什么是编译时注解?它在程序编译期间由注解处理器处理。编译期:Java语言的编译期是一个不确定的运行过程,因为它可能是将*.java文件转换成*.class文件的过程;它也可以指将字节码转换为机器码的过程;可能是直接将*.java编译成本地机器码的过程的runtime:从JVM加载字节码文件到内存中,最终使用后卸载的过程,属于runtime的范畴。AnnotationProcessingToolapt注解处理工具apt(AnnotationProcessingTool),是Sun公司提供的帮助注解处理过程的工具,apt是用来操作Java源文件的,不是编译类。它是javac的一个工具,中文意思是编译时注解处理器。APT可用于在编译时扫描和处理注释。可以通过APT获取标注对象的标注及相关信息。获取到这些信息后,我们就可以根据需求自动生成一些代码,免去手工编写的麻烦。注意,获取注解和生成代码都是在代码编译时完成的,相对于运行时反射处理注解,大大提高了程序性能。APT的核心是AbstractProcessor类。一般情况下,使用APT工具只能生成部分文件(不仅是我们想象中的class文件,还有xml文件等),不能修改原文件信息。但是这个时候估计会有疑问了,那么Lombok不就是在我们原来的文件里面加了一些信息吗?后面会详细解释,这里简单介绍一下,其实Lombok修改了Java中的抽象语法树AST来修改其原有类的信息。接下来,我们将演示如何使用APT工具生成类文件,然后我们将讨论Lombok如何修改现有类中的属性。定义注解首先当然要定义自己的注解@Retention(RetentionPolicy.SOURCE)//注解只保留在源码中@Target(ElementType.TYPE)//用于修改类public@interfaceGeneratePrint{Stringvalue();}Retention注解上有一个属性值,它是一个RetentionPolicy类型的枚举类,RetentionPolicy枚举类中有三个值。publicenumRetentionPolicy{SOURCE,CLASS,RUNTIME}SOURCE修饰注解:修饰注解,表示注解信息会被编译器丢弃,不会留在class文件中,注解信息只会留在源文件中CLASS修饰注解:表示注解的信息在程序编译时保留在class文件(字节码文件)中,但不会被虚拟机读取。运行时被RUNTIME修改的注解:表示注解的信息在程序编译时保留在类文件(字节码文件)中,在运行时由虚拟机保存。所以它可以通过反射调用,所以在正常运行时使用注释。这个参数Target注解上面还有一个属性值,是ElementType类型的枚举。它用于修改此注释的工作位置。publicenumElementType{TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE}定义注解处理器推荐一个SpringBoot基础教程和实例:https://github.com/javastacks...如果我们要定义一个注解处理器,那么就需要继承AbstractProcessor类。继承后基本框架类型如下@SupportedSourceVersion(SourceVersion.RELEASE_8)@SupportedAnnotationTypes("aboutjava.annotion.MyGetter"))}@Overridepublicbooleanprocess(Setannotations,RoundEnvironmentroundEnv){returntrue;}}我们可以看到子类中有上面两个注解,注解说明如下@SupportedSourceVersion:表示支持的Java版本@SupportedAnnotationTypes:表示处理器要处理的注解继承父类的两个方法班级。该方法描述如下。init方法:主要是在编译时获取一些环境信息。process方法:编译器在编译时执行的方法。那就是我们写具体逻辑的地方。我们是在演示如何通过继承AbstractProcessor类在编译时生成类,所以我们把生成类的代码写在process方法中。如下。@Overridepublicbooleanprocess(Setannotations,RoundEnvironmentroundEnv){StringBuilderbuilder=newStringBuilder().append("packageaboutjava.annotion;\n\n").append("publicclassGeneratedClass{\n\n")//打开类.append("\tpublicStringgetMessage(){\n")//打开方法.append("\t\treturn\"");//为每个javax.lang.model.element.Element用CustomAnnotation注释for(Elementelement:roundEnv.getElementsAnnotatedWith(MyGetter.class)){StringobjectType=element.getSimpleName().toString();//这是附加到返回语句builder.append(objectType)。append("sayshello!\\n");}builder.append("\";\n")//结束return.append("\t}\n")//关闭方法.append("}\n");//关闭类try{//wr引用文件JavaFileObjectsource=processingEnv.getFiler().createSourceFile("aboutjava.annotion.GeneratedClass");作家writer=source.openWriter();writer.write(builder.toString());writer.flush();作者.close();}catch(IOExceptione){//注意:调用e.printStackTrace()会打印IO错误//第一次运行后文件已经存在,这是正常的}returntrue;}定义使用上面的两个类注解类(测试类)是基础工具类,一个定义注解,一个定义注解处理器。接下来,让我们在类加上我们的自定义注释类上定义一个测试类(TestAno.java)。@MyGetterpublicclassTestAno{publicstaticvoidmain(String[]args){System.out.printf("1");这样我们就可以在编译的时候生成文件了。接下来,我们将演示如何在编译过程中生成文件。这个时候不用着急直接编译javac。MyGetter类是注解类,MyGetterProcessor是注解类的处理器。然后我们会在编译TestAnoJava文件的时候触发处理器。因此这两个类不能一起编译。先给大家看下我的目录结构aboutjava--annotation--MyGetter.java--MyGetterProcessor.java--TestAno.java那么我们先编译注解类和注解处理器类javacaboutjava/annotion/MyGett*Next编译我们的测试类.这时候我们需要在编译的时候加入processor参数来指定相关的注解处理类。javac-processoraboutjava.annotion.MyGetterProcessoraboutjava/annotion/TestAno.java动态图中可以看到,Java文件是自动生成的。近期热点文章推荐:1.1000+Java面试题及答案(2022最新版)2.厉害了!Java协程来了。..3.SpringBoot2.x教程,太全面了!4.不要用爆破爆满画面,试试装饰者模式,这才是优雅的方式!!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!
