hello,小伙伴们,大家好,我是沉默王二,一枚沉默但有趣的程序员。这是《教妹学 Java》专栏的第五篇文章,我们来谈谈“Java 程序在编译期时发生了什么”。
强烈推荐:我在 GitHub 上发现了一个宝藏项目,里面罗列了几百本 Java 经典电子书,包含入门、工具、框架、数据库、并发编程、底层、性能优化、设计模式、计算机网络、操作系统、数据结构与算法、面试、大数据、架构等等方面,应有尽有,需要的小伙伴可以在公众号后台回复「Java」 按照目录自取。
上一篇文章发表后,就有小伙伴留言说要一直教下去,我这就赶紧安排上。专栏名是不是很带劲?对,力求超凡脱俗,我相信小伙伴们在阅读的过程中一定能感受到思维的乐趣,还能真的学习到知识。
再次强调,《教妹学 Java》专栏面向的是零基础的 Java 学习者,我希望这个专栏能够带领 Java 初学者轻松迈进编程世界的大门,并且能够读写编写出规范、有用的 Java 代码。同时,为后续的深入学习打下坚实的基础。
我妹(亲妹)今年上大学了,学的计算机编程,立志像我一样做一名正儿八经的 Java 程序员。我一开始极力反对,因为程序员这行业容易掉头发,作为一名需要美貌的女生,掉头发可不太妙。
但我妹说了一句略带嘲讽的话“二哥,你为啥发量那么茂密?”,我顿时无言以对。那不如做点更积极的事情吧,比如说写点有趣的文章,教我妹更快地掌握 Java 这门编程语言。
------正儿八经的分割线--------
“二哥,看了上一篇 Hello World 的程序后,我很好奇,它是怎么在 Run 面板里打印出‘三妹,少看手机少打游戏,好好学,美美哒’呢?”三妹咪了一口麦香可可奶茶后对我说。
“三妹,我们通常把 Java 分为编译期和运行时,弄清楚这两个阶段就知道原因了。由于运行时涉及到的内容比较多,这篇文章我们先来说说编译期,等学习了 Java 虚拟机的一些知识后再说道说道运行时。”
贴一下 HelloWorld 这段代码:
/** * @author 微信搜「沉默王二」,回复关键字 PDF */public class HelloWorld { public static void main(String[] args) { System.out.println("三妹,少看手机少打游戏,好好学,美美哒。"); }}
点击 IDEA 工具栏中的锤子按钮(Build Project,编译整个项目),如下图所示。
这时候,就可以在 src 的同级目录 target 下找到一个名为 HelloWorld.class 的文件。
如果找不到的话,在目录上右键选择「Reload from Disk,从磁盘上重新加载」,如下图所示:
可以双击打开它。
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.itwanger.five;public class HelloWorld { public HelloWorld() { } public static void main(String[] args) { System.out.println("三妹,少看手机少打游戏,好好学,美美哒。"); }}
IDEA 默认会用 Fernflower 反编译工具将字节码文件(后缀为 .class 的文件,也就是 Java 源代码编译后的文件)反编译为我们可以看得懂的 Java 源代码。但实际上,字节码文件并不是这样的,而是:
// class version 58.0 (58)// access flags 0x21public class com/itwanger/five/HelloWorld { // compiled from: HelloWorld.java // access flags 0x1 public <init>()V L0 LINENUMBER 6 L0 ALOAD 0 INVOKESPECIAL java/lang/Object.<init> ()V RETURN L1 LOCALVARIABLE this Lcom/itwanger/five/HelloWorld; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x9 public static main([Ljava/lang/String;)V L0 LINENUMBER 8 L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "\u4e09\u59b9\uff0c\u5c11\u770b\u624b\u673a\u5c11\u6253\u6e38\u620f\uff0c\u597d\u597d\u5b66\uff0c\u7f8e\u7f8e\u54d2\u3002" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L1 LINENUMBER 9 L1 RETURN L2 LOCALVARIABLE args [Ljava/lang/String; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1}
是不是就有点懵逼了?新手看到这个很容易头大,不过不要担心,后面我再和大家一块深入研究一下,这里就是感受一下字节码的魅力。
那这个字节码文件是怎么看到的呢?可以通过 IDEA 菜单栏中的「View」→「Show Bytecode」查看,如下图所示。
PS:字节码并不是机器码,操作系统无法直接识别,需要在操作系统上安装不同版本的 Java 虚拟机(JVM)来识别。通常情况下,我们只需要安装不同版本的 JDK(Java Development Kit,Java 开发工具包)就行了,它里面包含了 JRE(Java Runtime Environment,Java 运行时环境),而 JRE 又包含了 JVM。
Windows、Linux、MacOS 等操作系统都有相应的 JDK,只要安装好了 JDK 就有了 Java 语言的运行时环境,就可以把一份字节码文件在不同的平台上运行了。可以在 Oracle 官网上下载不同版本的 JDK。
PPS:为什么要查看字节码呢?查看字节码文件更容易让我们搞懂 Java 代码背后的原理,比如搞懂 Java 中的各种语法糖的本质。
相比于 IDEA 自带的「Show Bytecode」功能,我更推荐 jclasslib 这款插件,可以在插件市场中安装(我已经安装过了)。
安装完成之后,点击 View -> Show Bytecode With jclasslib 即可通过 jclasslib 查看字节码文件了(点击之前,光标要停留在对应的类文件上),如下图所示。
使用 jclasslib 不仅可以直观地查看类对应的字节码文件,还可以查看类的基本信息、常量池、接口、字段、方法等信息,如下图所示。
也就是说,在编译阶段,Java 会将 Java 源代码文件编译为字节码文件。在这个阶段,编译器会进行一些检查工作,比如说,某个关键字是不是写错了,语法上是不是符合预期了,不能有很明显的错误,否则带到运行时再检查出来就会比较麻烦了。
“好了,三妹,今天我们就学到这吧。”转动了一下僵硬的脖子后,我对三妹说。
“好的,二哥,我也要按照你说的,研究一下字节码,感觉挺好玩的。”三妹似乎对未来充满了希望,这正是我想看到的。
这是《教妹学 Java》专栏的第五篇文章,能看到这里的小伙伴都是最帅的,最美的,升职加薪就是你了👍。
写这个专栏的初衷就是为了帮助那些零基础学 Java,或者自学 Java 感觉特别痛苦,特别难入门的小伙伴。
另外,我还创建了一些「技术交流群」,群里氛围很不错,有不少小伙伴会分享一些校招或者社招经验,更重要的是,群里时不时会有「红包」等福利,当然,群里不允许任何形式的广告。扫描下方的二维码,回复「加群」即可。
示例代码已经同步到 GitHub,地址为 github.com/itwanger,也可以点击阅读原文进行跳转,欢迎 star。