深入拆解Java虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
立即订阅
28017 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么我们要学习Java虚拟机?
免费
模块一:Java虚拟机基本原理 (12讲)
01 | Java代码是怎么运行的?
02 | Java的基本类型
03 | Java虚拟机是如何加载Java类的?
04 | JVM是如何执行方法调用的?(上)
05 | JVM是如何执行方法调用的?(下)
06 | JVM是如何处理异常的?
07 | JVM是如何实现反射的?
08 | JVM是怎么实现invokedynamic的?(上)
09 | JVM是怎么实现invokedynamic的?(下)
10 | Java对象的内存布局
11 | 垃圾回收(上)
12 | 垃圾回收(下)
模块二:高效编译 (12讲)
【工具篇】 常用工具介绍
13 | Java内存模型
14 | Java虚拟机是怎么实现synchronized的?
15 | Java语法糖与Java编译器
16 | 即时编译(上)
17 | 即时编译(下)
18 | 即时编译器的中间表达形式
19 | Java字节码(基础篇)
20 | 方法内联(上)
21 | 方法内联(下)
22 | HotSpot虚拟机的intrinsic
23 | 逃逸分析
模块三:代码优化 (10讲)
24 | 字段访问相关优化
25 | 循环优化
26 | 向量化
27 | 注解处理器
28 | 基准测试框架JMH(上)
29 | 基准测试框架JMH(下)
30 | Java虚拟机的监控及诊断工具(命令行篇)
31 | Java虚拟机的监控及诊断工具(GUI篇)
32 | JNI的运行机制
33 | Java Agent与字节码注入
模块四:黑科技 (3讲)
34 | Graal:用Java编译Java
35 | Truffle:语言实现框架
36 | SubstrateVM:AOT编译框架
尾声 (1讲)
尾声 | 道阻且长,努力加餐
深入拆解Java虚拟机
登录|注册

27 | 注解处理器

郑雨迪 2018-09-21
注解(annotation)是 Java 5 引入的,用来为类、方法、字段、参数等 Java 结构提供额外信息的机制。我先举个例子,比如,Java 核心类库中的@Override注解是被用来声明某个实例方法重写了父类的同名同参数类型的方法。
package java.lang;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Override注解本身被另外两个元注解(即作用在注解上的注解)所标注。其中,@Target用来限定目标注解所能标注的 Java 结构,这里@Override便只能被用来标注方法。
@Retention则用来限定当前注解生命周期。注解共有三种不同的生命周期:SOURCECLASSRUNTIME,分别表示注解只出现在源代码中,只出现在源代码和字节码中,以及出现在源代码、字节码和运行过程中。
这里@Override便只能出现在源代码中。一旦标注了@Override的方法所在的源代码被编译为字节码,该注解便会被擦除。
我们不难猜到,@Override仅对 Java 编译器有用。事实上,它会为 Java 编译器引入了一条新的编译规则,即如果所标注的方法不是 Java 语言中的重写方法,那么编译器会报错。而当编译完成时,它的使命也就结束了。
我们知道,Java 的注解机制允许开发人员自定义注解。这些自定义注解同样可以为 Java 编译器添加编译规则。不过,这种功能需要由开发人员提供,并且以插件的形式接入 Java 编译器中,这些插件我们称之为注解处理器(annotation processor)。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Java虚拟机》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(15)

  • lovedebug
    讲的很好,赞。结合java语法看印象更深
    2018-09-27
    4
  • 聚变
    编译时生成与 运行时使用cglib等类库生成的字节码,在性能和使用场景上有什么区别吗??

    作者回复: Cglib等字节码工具会影响启动性能,峰值性能上没啥区别。

    如果对字节码不熟的话,用注解处理器比较容易些。另一方面,字节码处理工具更强大些,能做很多源代码不能做的。

    2018-09-21
    4
  • godtrue
    嗯,之前写过注解方面的功能,不过虽然能自定义注解,也能明白Java语言层面的有关注解相关的知识点,但是往下怎么样就不太清楚了?
    注解代码本质也是代码,也会被编译为.class文件,然后在JVM上面被转换成机器码,然后被计算机执行,不过感觉他好特别,他的存在仅是为了是编码更简洁吗?
    读之前我就在想上面的问题,文中虽然没有介绍这些内容,不过介绍了其他的内容也挺好!

    小结一下:
    1:注解处理器-本质也是代码,以插件的形式存在,以插件的形式接入Java编译器,这些插件有什么用呢?

    2:注解处理器的作用?
    注解处理器有三个作用
    2-1:可以为Java编译器添加一些编译规则,这也就是传说中的自定义注解,它可以定义一些编译规则,这些编译规则会以插件的形式提供给Java编译器。
    2-2:可以修改已有的JAVA源文件(不推荐,为什么呢?因为本质上注解处理器不能修改已有的JAVA源代码,但是它可以修改有java源代码生成的抽象语法树,从而使生成的字节码发生变化,不过对抽象语法树的修改修改设计了java编译器的内部API,这部分很可能随着版本的变更而失效,所以,才不推荐使用的,存在埋深坑的隐患。)
    2-3:可以生成一些新的JAVA源文件

    3:元注解-给注解使用的注解就是元注解,这些注解是JDK的开发人员提前定义了的,也同样是以插件的形式接入Java编译器的。注意:所有的注解处理器都必须实现Processor接口,这个接口中有四个方法,每个方法都有其特殊的作用在,详情需要回头细看。另外,JDK提供了一个实现Processor接口的抽象类AbstractProcessor,这个抽象类实现了Processor接口的其中三个方法。

    4:自定义的注解被编译为.class文件后,便可以将其注册为Java编译器的插件了,注册方法有两种,祥看专栏内容吧!

    5:Java源代码的编译过程分为三个步骤
         5-1:解析源文件生成抽象语法树
         5-2:调用已注册的注解处理器(注解处理器有两种注册到JAVA编译器的方式)
         5-3:生成字节码
         5-4:如果5-2步中,注解处理器生成了新的源代码,那么JAVA编译器将重复第5-1/5-2步,直到不再生成新的源代码。

    作者回复: 注解相当于给某些代码贴了个标签。我们既可以通过注解处理器在编译时解析这些标签,也可以在运行时通过反射解析这些标签。解析后都会有一系列动作,这些动作就是对标签语义的诠释。

    2018-09-24
    3
  • 奇奇
    老师,这个 ExecutableElement targetAsKey = getExecutable(annotation, "value"); 这一句是干嘛的,我看语义是找出所有名字是value的方法?难道不应该找的是value所指向的类吗?
    2019-04-25
    1
  • 白三岁
    spring中的那些注解也是通过注解处理器实现的吗。我们项目中一般好像都是通过spring的aop来实现自定义注解的功能。
    2018-09-28
    1
  • 小美
    郑老师 有个问题我一直想不明白?java 源码生成语法树 java APT 处理器处理后生成代码, 从新走那个过程 有重复生成了 那不是死循环了吗?可能是自己知识浅薄 麻烦在这点上正老师能指点下☺️ 自己水平比较low 模仿了写一直没成功☺️ 不知道郑老师能发一个demo 工程吗
    2018-09-23
    1
  • Egos
    问一下RetentionPolicy.CLASS 的使用场景。有一些用来生成Java 文件的注解是可以使用SOURCE的,但是用了CLASS。
    2018-09-22
    1
  • 补心
    Lombok随着Java版本的问题,是不是有可能没法使用。

    作者回复: 有可能,因为用的是internal API。

    2018-09-21
    1
  • 在DDD的路上
    厉害了,但是我有个问题想请教一下: 自定义有 A和B 两个注解 都有一个 String类型的 value属性,如果A注解 引用了 B 注解 作为A的属性,那么如何让A注解的 value 传给 B属性呢
    ----------------------------
    public @interface A {
        String name();
        B b() default @B(name = "这里怎么将A的name属性传给 B注解的name呢");
    }
    // 有这样的组合注解需求,望大牛指点!
    2019-11-16
  • 松花皮蛋me
    反射在运行时,注解解释器在编译时
    2019-03-16
  • 孜孜
    @Getter 和例子自己定义的@CheckGetter 一起使用,@CheckGetter先生效。有点搞不明白Lombok和自己定义的执行顺序。
    2019-03-12
  • 金龟
    CheckGetterProcessor这个是怎么用的??我感觉我没有运行起来一个类里没有getter方法,我一样能够编译通过。
    2019-01-29
  • 山顶的洞
    自定义注解都是aop实现的吗?好像没看到过注解处理器。
    2018-12-02
  • lewis
    老师你好,我在使用Annotation Processor过程中,遇到了一个问题,比如某个Element是一个方法,我想获取这个方法的返回值类型,当这个返回值是泛型的时候,无法获取全路径的类型;比如返回值是自定义类型com.xxx.module.domain.UserInfo这个类型,通过下面的语句只能知道返回值是字面量UserInfo,而不是com.xxx.module.domain.UserInfo这个全路径类型 。
     ExecutableElement methodElement = ExecutableElement.class.cast(element);
                TypeMirror returnType = methodElement.getReturnType();
                TypeName returnTypeName = ClassName.get(returnType);
    这个returnTypeName只是UserInfo,不是com.xxx.module.domain.UserInfo,拿不到UserInfo的包路径信息,通过messager提示说是找不到com.xxx.module.domain这个包,请老师指导
    2018-10-04
  • mtfelix
    不错哦
    2018-09-22
收起评论
15
返回
顶部