点击上方蓝色“方志朋”,选择“设为星标”

回复“666”获取独家整理的学习资料!

来源 | https://urlify.cn/y2UnAn

相信大家在项目中都使用过Lombok,因为能够简化我们许多的代码,但是该有的功能一点也不少。

那么lombok到底是个什么呢,lombok是一个可以通过简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 Java 代码的工具,简单来说,比如我们新建了一个类,然后在其中写了几个字段,然后通常情况下我们需要手动去建立getter和setter方法啊,构造函数啊之类的,lombok的作用就是为了省去我们手动创建这些代码的麻烦,它能够在我们编译源码的时候自动帮我们生成这些方法。

那么Lombok到底是如何做到这些的呢?其实底层就是用到了编译时注解的功能。

Lombok如何使用

Lombok是一个开源项目,代码是在lombok中,如果是gradle项目的话直接在项目中引用如下即可。

compile ("org.projectlombok:lombok:1.16.6")

功能

那么Lombok是做什么呢?其实很简单,一个最简单的例子就是能够通过添加注解自动生成一些方法,使我们代码更加简洁易懂。例如下面一个类。

 1 @Data2 public class TestLombok {3    private String name;4    private Integer age;56    public static void main(String[] args) {7        TestLombok testLombok = new TestLombok();8        testLombok.setAge(12);9        testLombok.setName("zs");
10    }
11 }

我们使用Lombok提供的Data注解,在没有写get、set方法的时候也能够使用其get、set方法。我们看它编译过后的class文件,可以看到它给我们自动生成了get、set方法。

 1 public class TestLombok {2    private String name;3    private Integer age;45    public static void main(String[] args) {6        TestLombok testLombok = new TestLombok();7        testLombok.setAge(12);8        testLombok.setName("zs");9    }
10
11    public TestLombok() {
12    }
13
14    public String getName() {
15        return this.name;
16    }
17
18    public Integer getAge() {
19        return this.age;
20    }
21
22    public void setName(String name) {
23        this.name = name;
24    }
25
26    public void setAge(Integer age) {
27        this.age = age;
28    }
29
30}

当然Lombok的功能不止如此,还有很多其他的注解帮助我们简便开发,网上有许多的关于Lombok的使用方法,这里就不再啰嗦了。正常情况下我们在项目中自定义注解,或者使用Spring框架中@Controller、@Service等等这类注解都是运行时注解,运行时注解大部分都是通过反射来实现的。而Lombok是使用编译时注解实现的。那么编译时注解是什么呢?

编译时注解

注解(也被成为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。——————摘自《Thinking in Java》

Java中的注解分为运行时注解编译时注解,运行时注解就是我们经常使用的在程序运行时通过反射得到我们注解的信息,然后再做一些操作。而编译时注解是什么呢?就是在程序在编译期间通过注解处理器进行处理。

  • 编译期:Java语言的编译期是一段不确定的操作过程,因为它可能是将*.java文件转化成*.class文件的过程;也可能是指将字节码转变成机器码的过程;还可能是直接将*.java编译成本地机器代码的过程

  • 运行期:从JVM加载字节码文件到内存中,到最后使用完毕以后卸载的过程都属于运行期的范畴。

注解处理工具apt

注解处理工具apt(Annotation Processing Tool),这是Sun为了帮助注解的处理过程而提供的工具,apt被设计为操作Java源文件,而不是编译后的类。

它是javac的一个工具,中文意思为编译时注解处理器。APT可以用来在编译时扫描和处理注解。通过APT可以获取到注解和被注解对象的相关信息,在拿到这些信息后我们可以根据需求来自动的生成一些代码,省去了手动编写。注意,获取注解及生成代码都是在代码编译时候完成的,相比反射在运行时处理注解大大提高了程序性能。APT的核心是AbstractProcessor类。

正常情况下使用APT工具只是能够生成一些文件(不仅仅是我们想象的class文件,还包括xml文件等等之类的),并不能修改原有的文件信息。

但是此时估计会有疑问,那么Lombok不就是在我们原有的文件中新增了一些信息吗?我在后面会有详细的解释,这里简单介绍一下,其实Lombok是修改了Java中的**抽象语法树AST**才做到了修改其原有类的信息。

接下来我们演示一下如何用APT工具生成一个class文件,然后我们再说Lombok是如何修改已存在的类中的属性的。

定义注解

首先当然我们需要定义自己的注解了

1 @Retention(RetentionPolicy.SOURCE)
2 @Target(ElementType.TYPE)
3 public @interface GeneratePrint {
4
5    String value();
6 }

Retention注解上面有一个属性value,它是RetentionPolicy类型的枚举类,RetentionPolicy枚举类中有三个值。

1 public enum RetentionPolicy {
2
3    SOURCE,
4
5    CLASS,
6
7    RUNTIME
8 }
  • SOURCE修饰的注解:修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中

  • CLASS修饰的注解:表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候

  • RUNTIME修饰的注解:表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时。所以它能够通过反射调用,所以正常运行时注解都是使用的这个参数

Target注解上面也有个属性value,它是ElementType类型的枚举。是用来修饰此注解作用在哪的。

 1 public enum ElementType {2    TYPE,34    FIELD,56    METHOD,78    PARAMETER,9
10    CONSTRUCTOR,
11
12    LOCAL_VARIABLE,
13
14    ANNOTATION_TYPE,
15
16    PACKAGE,
17
18    TYPE_PARAMETER,
19
20    TYPE_USE
21 }

定义注解处理器

我们要定义注解处理器的话,那么就需要继承AbstractProcessor类。继承完以后基本的框架类型如下

 1 @SupportedSourceVersion(SourceVersion.RELEASE_8)2 @SupportedAnnotationTypes("aboutjava.annotion.MyGetter")3 public class MyGetterProcessor extends AbstractProcessor {4    @Override5    public synchronized void init(ProcessingEnvironment processingEnv) {6    super.init(processingEnv);7    }89    @Override
10    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
11        return true;
12    }
13 }

我们可以看到在子类中上面有两个注解,注解描述如下

  • @SupportedSourceVersion:表示所支持的Java版本

  • @SupportedAnnotationTypes:表示该处理器要处理的注解

继承了父类的两个方法,方法描述如下

  • init方法:主要是获得编译时期的一些环境信息

  • process方法:在编译时,编译器执行的方法。也就是我们写具体逻辑的地方

我们是演示一下如何通过继承AbstractProcessor类来实现在编译时生成类,所以我们在process方法中书写我们生成类的代码。如下所示。

1 @Override2 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {3    StringBuilder builder = new StringBuilder()4            .append("package aboutjava.annotion;\n\n")5            .append("public class GeneratedClass {\n\n") 6            .append("\tpublic String getMessage() {\n") 7            .append("\t\treturn \"");8    9    for (Element element : roundEnv.getElementsAnnotatedWith(MyGetter.class)) {
10        String objectType = element.getSimpleName().toString();
11
12        builder.append(objectType).append(" says hello!\\n");
13    }
14    builder.append("\";\n")
15            .append("\t}\n")
16            .append("}\n");
17    try {
18        JavaFileObject source = processingEnv.getFiler().createSourceFile("aboutjava.annotion.GeneratedClass");
19        Writer writer = source.openWriter();
20        writer.write(builder.toString());
21        writer.flush();
22        writer.close();
23    } catch (IOException e) {
24
25
26    }
27    return true;
28 }

定义使用注解的类(测试类)

上面的两个类就是基本的工具类了,一个是定义了注解,一个是定义了注解处理器,接下来我们来定义一个测试类(TestAno.java)。我们在类上面加上我们自定的注解类。

1 @MyGetter
2 public class TestAno {
3
4    public static void main(String[] args) {
5        System.out.printf("1");
6    }
7 }

这样我们在编译期就能生成文件了,接下来演示一下在编译时生成文件,此时不要着急直接进行javac编译,MyGetter类是注解类没错,而MyGetterProcessor是注解类的处理器,那么我们在编译TestAnoJava文件的时候就会触发处理器。因此这两个类是无法一起编译的。

先给大家看一下我的目录结构

aboutjava2
-- annotion3
-- MyGetter.java4
-- MyGetterProcessor.java5
-- TestAno.java

所以我们先将注解类和注解处理器类进行编译

javac aboutjava/annotion/MyGett*

接下来进行编译我们的测试类,此时在编译时需要加上processor参数,用来指定相关的注解处理类。

javac -processor aboutjava.annotion.MyGetterProcessor aboutjava/annotion/TestAno.java

大家可以看到动态图中,自动生成了Java文件。


热门内容:
  • 《最受欢迎的男友职业排行榜Top10》

  • CTO 写的代码,真是绝了

  • 超牛逼的 Feed 流系统设计!

  • 今天终于搞懂了:为什么 Java 的 main 方法必须是 public static void?

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。)

Lombok经常用,却不知道它的原理是什么相关推荐

  1. ant如何形成时间轴和图库_Python数据可视化常用4大绘图库原理详解_python

    这篇文章主要介绍了Python数据可视化常用4大绘图库原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 今天我们就用一篇文章,带大家梳理mat ...

  2. 常用热修复方案以及原理

    常用热修复方案以及原理 bsdiff.exe 比对文件不同 bspatch.exe 生成增量包 增量级别更新,应用很广泛,抖音微信都有使用增量更新 所有的热修复都是使用 反射和类加载机制完成热修复,和 ...

  3. 铣扁机的常用加工方法及构造原理

    铣扁机是两个面对称的铣扁,通常所指的就是轴类产品的扁位对称切削位置.铣扁机的常用加工方法以及构造原理是怎样的呢? 铣扁机的加工方法有三种,一是小卧铣,二是铣床,三是铣扁机. 小窝铣是一些精度不高的轴类 ...

  4. Lombok经常用,但是你知道它的原理是什么吗?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:不学无数的程序员 地址:my.oschina.net/u/4 ...

  5. Lombok 天天用,却不知道它的原理是什么?

    相信大家在项目中都使用过Lombok,因为能够简化我们许多的代码,但是该有的功能一点也不少. 那么lombok到底是个什么呢,lombok是一个可以通过简单的注解的形式来帮助我们简化消除一些必须有但显 ...

  6. python各个绘图的作用,深度讲解Python四大常用绘图库的“绘图原理”

    转自:数据分析与统计学之美 为什么要写这篇文章? 最近有不少粉丝来问我,Python绘图库太多,我知不知道学哪一个?即使我选择了某一个绘图库后,我也不知道怎么学,我不知道第一步做什么,也不知道接下来该 ...

  7. 肝!深度讲解Python四大常用绘图库的“绘图原理”

    为什么要写这篇文章? 最近有不少粉丝来问我,Python绘图库太多,我知不知道学哪一个?即使我选择了某一个绘图库后,我也不知道怎么学,我不知道第一步做什么,也不知道接下来该怎么做,四个字一学就忘. 其 ...

  8. python常用代码_Python常用算法学习(3)(原理+代码)——最全总结

    1,什么是算法的时间和空间复杂度 算法(Algorithm)是指用来操作数据,解决程序问题的一组方法,对于同一个问题,使用不同的算法,也许最终得到的结果是一样的,但是在过程中消耗的资源和时间却会有很大 ...

  9. 深度讲解 Python 四大常用绘图库的“绘图原理”

    作者 | 黄伟呢 整理 | 杨碧玉 出品 | 数据分析与统计学之美(ID:gh_21c25c7e71d0) 头图 |  CSDN 下载自视觉中国 为什么要写这篇文章? 最近有不少粉丝来问我,Pytho ...

最新文章

  1. GridView导出到Excel或Word文件
  2. Hdu 3062. Party
  3. php 回到顶部,jquery如何实现点击网页回到顶部效果?(图文+视频)
  4. 华为鸿蒙话题作文800字,关于鸿蒙OS 华为最高层发布最新通知:统一口径-华为,智能手机,鸿蒙...
  5. 制作多系统启动盘教程_制作U盘启动盘教程
  6. censtos6.5安装java 8_Centos6.5 安装JDK
  7. 挑战程序设计竞赛(第2版) 第3章笔记
  8. java jdbc 批量更新_java,jdbc,大量数据update更新效率很慢,哪位大神可怜可怜我吧...
  9. python中fac函数_python系列-基础
  10. 【AllenNLP入门教程】: 2、基于Allennlp2.4版本的一些使用技巧
  11. 企业设计图纸 无纸化图纸管理方案
  12. 网站搭建的流程是什么
  13. 怎么用HTML表格中加上线条,如何在html的表格中加入边框线
  14. [Python-turtle]正弦定理能擦出多漂亮的火花?【1】
  15. 小红书口碑营销怎么做?小红书笔记结构剖析及场景营销
  16. ARPG、MMORPG、MOBA、卡牌类、棋盘类游戏服务器架构图
  17. IIS URL 重写
  18. jupyter notebook把txt文件写成所需格式的txt文件
  19. Excel表格 |两列数据(多列)合并一列且自动换行
  20. 操作系统存储管理实验课程设计报告

热门文章

  1. Git 版本还原命令
  2. 第39-43课 thinkphp5完成商品会员价格功能(后置勾子afterInsert)
  3. 给大家推荐8个SpringBoot精选项目
  4. E: GPG 错误:http://developer.download.nvidia.com Release: 下列签名无效: NODATA 1 NODATA 2...
  5. jquery 获取一组元素的选中项 - 函数、jquery获取复选框值、jquery获取单选按钮值...
  6. spring WebServiceTemplate 调用 axis1.4 发布的webservice
  7. java基础之——类的初始化顺序(转载)
  8. (转)利用ArcScene进行三维地形模拟
  9. 用JSP+JDBC开发Web程序
  10. 尚育鹏:Leetcode刷题总结(数组)