赞
踩
.class
的文件形式存在本地磁盘上,在
Class
文件中描述的各类信息最终都需要加载到虚拟机中之后才能被运行和使用
1.类加载过程
虚拟机把类的数据从.class文件加载到内存,并对class文件中的数据进行校验、转换、解析、初始化等操作后,最终形成可以被虚拟机识别并使用的Class对象的过程就叫做“虚拟机的类加载”,主要包括为3大阶段。
即
类加载子系统
其中链接包含了验证,准备,解析三个子阶段,下面根据这三大阶段一一解释
需要注意的是,这里的加载是整个类加载子系统的一个小阶段,在这个阶段,java虚拟机
需要完成以下三件事:
确保class文件符合java虚拟机要求
简单的来说为被static
修饰的变量赋初始值,分配内存,这些变量所使用的内存在方法区进行分配,JKD7
之前虚拟机将其存放于永久代,JKD8
及以后,类变量会随着Class对象一起放在堆中,实例变量会在对象实例化时随对象一起分配到堆中
这里不赘述
这是类加载过程的最后一步,在之前的准备阶段,类变量已经赋初始值了,这里的初始化就是虚拟机根据程序员书写静态变量,静态代码块的顺序执行赋值等动作,但大家需要注意以下注意点
public class Demo {
public static void main(String[] args) {
System.out.println(p.i);
}
}
class p{
{
i = 2;
}
static int i = 1;
}
这段代码在编译器是不会报错的,但是如果在代码块中执行System.out.println(i);
就会报错:超前引用,即可以赋值,但不可访问
另外,在Java虚拟机规范中明确指出了,有且只有6种情况必须立即对类进行初始化
2.类加载器
上面的架构图已经揭示了类加载器的作用,类加载器类加载器(class loader)将Java类从本地磁盘加载到Java虚拟机中,并同时创建了该类的Class对象,实现了“通过一个类的全限定类名来获取此类的二进制字节流”功能。通过一个例子将类加载器和类加载过程做一个说明
一个car
类在被编译后形成了class
文件,被类加载器加载到jvm
中并分配了内存和唯一一个class
对象,通过这个class对象就可以在堆中实例化多个car
实例对象
在java虚拟机
中,只存在两种不同的类加载器:
Bootstrap Classloader
,由C++编写,属于虚拟机一部分java.lang.Classloader
的类加载器,由Java语言编写,独立于虚拟机之外现在可能有人会问独立于虚拟机之外是什么意思了,请往下看:
它只负责加载你在环境变量中配置的<JAVA_HOME>\lib
下的内容,由于是C++编写,不能被java程序所引用,用以下代码演示
public class Demo {
public static void main(String[] args) {
System.out.println(Demo.class.getClassLoader().getParent().getParent());
}
}
当用户使用以上方式想要获取Bootstrap Classloader
是会失败的,返回的是null;
java.lang.Classloader
的类加载器Extension Class Loader
,扩展类加载器Application Class Loader(System Class Loader)
,应用程序类加载器这两个类都在sun.misc.Launcher
类中,属于内部类,不同的是 Extension Class Loader
只会加载<JAVA_HOME>\lib\ext
目录中的内容,而 Application Class Loader
则会加载我们自定义的类
展示一下他们的继承关系
需要提一下sun.misc.Launcher
,这是java虚拟机的入口程序,再次之前我们先要了解下虚拟机启动过程:
如何启动?java 命令
java命令是一个入口,执行的时候 会找到对应的执行文件,它会调用java api 接口(java api 接口和jvm 一起构成了jre),接口内部会调用其他接口创建虚拟机(虚拟内存,硬件,CPU等),
然后虚拟机会自动创建bootstrap 类加载器,我们再来看一下Launcher
类
我们发现这个类位于rt.jar
包下,而rt.jar
这个包由Bootstrap Classloader
负责加载,那么就可以说明引导类和扩展类加载器都是由Bootstrap Classloader
负责创建,到现在我们基本可以回答出刚才的问题了:
独立于虚拟机之外是什么意思:扩展类加载器和程序加载器这两个类加载器存在于jar
包,要依靠虚拟机创建的启动类加载器而创建的类加载器,这里要说明一下:
Class
对象,比较两个对象的Class实例对象是否相等,同一个classloader加载两个类使用“==”或equals做比较是正确的;两个不同的classloader分别加载两个类做比较就会有问题,两个实例不会相等;bootstrap类加载器,会创建 扩展类加载器和应用程序类加载器,他们执行原理为:
如果去加载不存在的类会抛出异常,不会返回null
文章写到这里基本上将类加载机制介绍完了,从头梳理一下jvm
的执行过程
java -jar
的命令启动, 会找到对应的执行文件,它会调用java api 接口(java api 接口和jvm 一起构成了jre),接口内部会调用其他接口创建虚拟机(虚拟内存,硬件,CPU等)文章还会持续更新和改正
参考文章:
java虚拟机执行过程
classloader详解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。