Day3|Hello World 背后的故事
作为很多语言入门教程的第一代码 ,在 Java 世界中,也以Hello,World作为我们的第一行代码。
但我们今天不止是输出一句话,而是要带你理解它背后的整个流程:
Java 程序是如何被写出来、编译、再一步步被执行的?
一、写下第一个 Java 程序
第一种方式
创建源码文件
用任意文本编辑器(如Notepad++/Windows记事本)新建文件:HelloWorld.java(注意保存时文件后缀是.java)
注意代码中class后的类名与文件名一致
全部代码必须写在类中(class 是基本单元)
main 方法是 JVM 定义的程序入口
System.out.println(...):向控制台输出一行文本
编译源代码
打开命令行,进入代码文件所在目录,保存的位置自行选择(最好是全英文的目录)
执行:
javac HelloWorld.java
然后执行dir命令,列出目录下所有文件,会发现产生了一个HelloWorld.class文件
这个class后缀的文件也就是我们最常说的字节码文件。
可以这样理解:
.java文件是我们能够认识的源码(任何字符、符号、逻辑),我们都有清晰的认知。
javac将.java文件按照一定的规则翻译(转换)成了JVM认识的文件内容。
当把字节码文件交给JVM的时候,JVM执行的内容就是字节码。
如果你尝试直接使用Notepad++打开class文件,你会看到下面的场景:
一堆乱码,偶尔能看到几个熟悉的单词。
如果你用UltraEdit打开字节码文件,并切换到16进制模式,你会看到如下场景:
如果你对字节码文件的内容很感兴趣,你可以尝试去阅读jvms17。
这个章节中专门描述了字节码文件的构成,后续的章节会详细的讲到。
运行
执行如下命令:
java HelloWorld
java命令可以理解为将字节码文件交给JVM运行,运行的结果就是在命令行窗口输出了"Hello, World!"。
通过以上三步,从代码编写、编译、运行,一个完整的Java程序运行周期基本都体现出来了。
反编译
上文中提到,我们如果直接打开字节码文件,内容是不适合人类阅读的。
JDK提供了一个反编译工具(javap)。
在刚才的目录执行:
javap -c HelloWorld
javap -c 会将字节码转换成人类可读的 JVM 指令。
这些指令,你需要去指令集查找。
比如:
详细的指令在后续的文章中也会讲到。
第二种方式
创建包、类
Day2的文章中,我们已经大致的讲了一下IDEA的使用过程。
这次我们直接新建一个package:
包名:com.lazy.snail.day3(可以自定义)
然后在包内新建一个类文件:
创建好之后的样子:
直接在大括号中编写代码:
public static void main(String[] args) {
System.out.println("Hello, World!");
}
编译源代码
直接build项目,源代码则会编译成字节码文件,不需要我们再输入javac命令,这些动作IDE已经帮我们完成,内嵌到某些按钮里面。
之前执行javac时,产生一个.class字节码文件,那么通过IDE编译的字节码在哪儿?
打开File-->Project Structure
然后找到编译文件的输出目录(这个目录也是可以自定义的,一般在项目根目录下有个默认值)
找到这个目录,字节码文件就在此处:
还有一个简便的方法:
勾选上Excluded Files,左侧是项目文件结构中就会出现一个编译文件的输出目录。
运行
IDE中怎么运行代码呢?还需要手敲java命令吗?
当然不需要了,IDE已经帮我们集成了。
这两个三角符号,都可以直接运行代码:
其实上一步的编译也可以忽略,直接点击三角符号,IDE会在运行前进行编译。
反编译
这里推荐一个IDEA的插件jclasslib
插件下载:File-->Settings-->Plugins-->Marketplace
直接搜索jclasslib安装即可。
使用:
打开jclasslib视图
右侧的jclasslib展示框会展示出这个类的所有信息(包括方法的字节码指令、类相关信息等)
在后续的学习过程中,会时不时的用上这个插件。
二、main方法
接下来我们大致的看一下main方法的代码
public static void main(String[] args){
// 具体逻辑
}
这个main方法是Java 程序的入口方法,是 JVM(Java 虚拟机)执行程序时第一个调用的方法。它的语法和签名是固定的,必须严格按照以下格式定义:
public是访问修饰符:表示该方法是公开的,可以被 JVM 从类的外部访问。
static是静态方法修饰符:表示该方法是静态的,属于类本身,而不是类的实例。
void是返回类型:表示该方法没有返回值。
main是方法名:这是 Java 语言规定的入口方法名称,不可更改。
String[] args是接受参数:接收命令行参数。args是一个字符串数组,表示运行程序时传入的参数。
三、执行流程
这张图大致的描述了源代码(.java)到字节码(.class)再到JVM运行的过程
四、一次编写,到处运行
这句话相信大家都听过,Java可以一次编写,到处运行,体现Java的跨平台性。
从上面简单的Hello,World程序,其实我们也能窥见一二。
开发者编写的 Java 代码,都会使用javac编译器将 .java文件编译成与平台无关的字节码(一种中间代码)。
字节码不是针对特定操作系统的机器码,而是面向 JVM 的指令集,格式统一(类似“通用机器语言”)。
不同操作系统(Windows、Linux、macOS 等)需要安装对应版本的 JVM。JVM 负责将字节码转换为当前平台的本地机器码,并执行它。(当学到JVM,接触虚拟机实现时,你就会发现,真正与平台相关的代码JVM实现已经帮我们处理了)
小结一下为什么Java能够实现“一次编译,到处运行”。
统一标准
字节码是平台中立的,所有 JVM 遵循相同的字节码规范(由 Java 虚拟机规范定义)
不同平台的 JVM 负责将同一份字节码“翻译”成本地机器码,开发者无需针对不同平台重新编译代码。
结语
- 第一次写下完整的 Java 程序
- 熟悉了源文件、编译、运行流程
- 明白了 Java 程序从源码到执行的幕后过程
- 学会使用命令行和IDEA两种方式运行代码
- 对main方法的结构与意义有了清晰认识
最后强烈推荐大家在学习过程中,多翻看官方文档。