什么是JDK、JRE和JVM
JDK(java development kit)
JDK 是Java语言的软件开发工具包(SDK)。在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin就是jvm,lib则是jvm工作所需要的类库,而jvm和lib合起来就称为jre。
JRE(java runtime environment)
JRE 包含jvm标准实现合Java核心类库。jre只是Java运行环境,并不是开发环境,所以没有包含任何开发工具(如编译器和打包工具)
JVM
JVM是 (java virtual machine)java虚拟机的缩写,JVM是一种用于计算机设备的规范,它是一个虚构出来的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。
由上图一目了然,JDK是Java的核心,包含Java运行环境Jre,Java开发工具(如编译器和调试器)。JRE是运行时环境,包含JVM标准实现和核心类库。JVM是整个java跨平台的核心,能够运行以Java语言写的程序。
Jvm类加载过程(运行原理)
开发人员写的Java代码通过Java编译器编译成与平台无关的字节码程序,也就是(.class,01二进制程序)文件
JVM整个类加载过程
JVM整个类加载过程分为三步
1.装载
装载过程由ClassLoader类加载器定位和加载class文件
2.链接
链接过程负责对二进制字节码格式进行校验,初始化装在类中的静态变量以及解析类中调用的接口,类。
完成检验后,初始化静态变量,为其赋予默认值。
最后对类中所有属性,方法进行验证。确保其调用的属性,方法存在,以及具备相应的权限。
3.初始化
初始化过程即为执行类中的静态初始化代码,构造器代码以及静态属性的初始化。
整个类加载过程总结起来就是 Java源文件—->编译器—->字节码文件—->JVM—->相应机器码
以此实现跨平台的过程
类加载器(ClassLoader)
从Java虚拟机的角度只存在两种类加载器:一种是启动类加载器,这个类加载器由C++语言实现(HotSpot虚拟机中),是虚拟机自身的一部分,另一种就是其他的类加载器,这些类加载器全部由java语言实现,独立于虚拟机外部,并且全部继承自ClassLoader。
从开发者角度,类加载器可以分为:
启动类加载器(Bootstrap)::负责将 Java_Home/lib下面的类库加载到内存中(比如rt.jar)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。
标准扩展类加载器(Extension):是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将Java_Home /lib/ext或者由系统变量 java.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。
应用程序类加载器(Application):是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加载器。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,因此一般称为系统(System)加载器。
除此之外,还有自定义的类加载器,它们之间的层次关系被称为双亲委派模型。该模型除了顶层加载器外,其余加载器都应该有自己的父类加载器,这种父子关系一般通过组合来实现而不是继承
所谓双亲委派机制,就是当一个加载器收到加载类请求时,首先将加载任务委托给自己的父类去加载,依次递归,只有当父类加载器不能加载时自己才去加载。
这样做的好处是便于保证类的唯一性,我们知道由不同加载器加载出来的同一class源文件也不是一个类,如果没有加载双亲委派机制,加载如Object这样的类时则难以保证它的唯一性,而在双亲委派机制下则不论由哪个加载器加载,最终都会委托给顶层的启动类加载器去加载它。