Java是如何运行应用程序的

运行一个Java应用程序,需要如下步骤:
用户编写完Java源代码后,经过Java编译器(javac命令),生成了.class文件。之后经过类装载器装载.class文件,之后再执行应用程序。

看似简单的过程,我们一步一步捋清楚。

.java文件会经过Java编译器生成.class文件,也就是字节码文件。这一步骤并没有什么好说的。这一部我们叫做编译,在cmd中通过javac命令实现。编译的结果并不是像C++或者汇编语言一样将内容转换为机器语言,而是转换为了能使jvm识别的语言。这种特定的语言最终能通过Java虚拟机执行。这也是为什么Java能跨平台的原因。是通过jvm运行应用程序实现跨平台的。

编译的过程又分为以下步骤:

1、词法分析:
	找到关键字的token流。比如说if、else、while、for等关键词有对应的token流。比如:do对应DO,else对应ELSE等。
2、语法分析:
	识别这些关键词是否符合要求。比如说while后面是否紧接着布尔类型的值等等。这一步会生成抽象树,具体可以学学编译原理。
3、语意分析:
	将没有构造方法的类型添加无参构造函数;对变量进行初始化;变量的值是否匹配等等。
4、生成字节码
	经过了语意分析后,形成的抽象树已经非常好了。然后将代码转换为JVM规范的字节码。JVM的架构模型是基于栈的,所有操作都是入栈和出栈进行操作的。

生成了.class文件后,经过类装载器装载内容。装载的步骤分别是:装载、链接、初始化。
装载
通过执行的类名,找到字节码,生成类。
默认的装载有三种Bootstrap ClassLoader、Extension ClassLoader、System ClassLoader。
Bootstrap ClassLoader(根加载器):负责加载Java核心类库。我们看看该加载器加载了什么库

URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL url : urls) {
	System.out.println(url.toExternalForm());
}
file:/D:/Program%20Files%20(x86)/Java/jre/lib/resources.jar
file:/D:/Program%20Files%20(x86)/Java/jre/lib/rt.jar
file:/D:/Program%20Files%20(x86)/Java/jre/lib/sunrsasign.jar
file:/D:/Program%20Files%20(x86)/Java/jre/lib/jsse.jar
file:/D:/Program%20Files%20(x86)/Java/jre/lib/jce.jar
file:/D:/Program%20Files%20(x86)/Java/jre/lib/charsets.jar
file:/D:/Program%20Files%20(x86)/Java/jre/lib/jfr.jar
file:/D:/Program%20Files%20(x86)/Java/jre/classes

这个加载器是jvm自身实现的。由C++实现
Extension ClassLoader(扩展加载器):用于加载jre/lib/ext目录下的类库。
System ClassLoader(系统加载器):一般用于加载jar包。存放于工程目录/bin目录下
通过以上三个加载器就能加载所有的类了。当然我们还可以自定义类加载器。要注意的是,并不是一次性把所有的类都加载完毕,而是需要用到哪个类时jvm才会选择去加载。

链接
1、验证class文件是否符合语法要求,比如说final不能被继承,代码是否完整等等。(用于避免开发人员任意修改class文件)。
2、为类变量初始化,比如说class A中有int a = 10;那么a变量会先赋值为0
3、解析,用于加载其他依赖的类。比如说类A中有Person类的对象,那么就会加载Person类对象。

初始化
为类变量附上正确的值,上述说了a变量的值为0,现在才是正式赋值为10。

最后JVM就执行程序了。

补充:在装载过程中,已经开启了JVM进程,也开启了GC回收机制。GC回收机制为守护线程,用于在后台管理、分配内存等。守护线程的优先级较低。在所有的非守护线程执行完毕后,守护线程(GC回收线程等)才会停止工作。此时才会关闭JVM进程。

猜你喜欢

转载自blog.csdn.net/new_Aiden/article/details/51824933