JVM-类的加载的机制和流程
Posted it江湖之旅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM-类的加载的机制和流程相关的知识,希望对你有一定的参考价值。
前言
昨天咱们把类的字节码读了一下,那么拿到字节码,咱们的jvm是如何去加载它的呢?这个是今天咱们主要分享的内容。
1.什么是类的加载机制以及他要做哪几件事情
JVM把class文件加载到内存里面,并对数据进行校验、准备、解析和初始化,最终能够被形成被JVM可以直接使用的Java类型的过程。
1:加载:查找并加载类文件的二进制数据
2:连接:就是将已经读入内存的类的二进制数据合并到JVM运行时环境中去
(1)验证:确保被加载类的正确性,符合JVM规范与安全【主要是验证类的字节码的结构,这个咱们上一篇的文章已经提到了】
(2)准备:为类的 静态变量 分配内存,并初始化它们,例如static int a=3,在此阶段会a被初始化为0
(3)解析:把常量池中的符号引用转换成直接引用
3:初始化:为类的静态变量赋初始值 【这一步才是真正的进行赋值操作】
看一段代码咱们加深一下理解(大家可以根据类的加载过程想想代码的执行结果):[提示:代码看起来不方便,可以在最下面点击阅读原文哈]
public class ClassLoadTest { /*随着类的加载,验证通过后,进行准备动作,就是分配内存 第3步在进行初始化给变量赋值,这个时候要new 对象了,那么new对象 一定会调用构造方法,于是a++,a变成1,b变成1 */
private static ClassLoadTest clt = new ClassLoadTest(); /*上面的步骤a为1了,但是这一步又将0赋值给了a */
private static int a=0;//准备动作初始化为0
//b没有赋值,延用之前的值就可以了
private static int b;//准备动作初始化为0
private ClassLoadTest(){
a++;
b++;
}
public static ClassLoadTest getInstance(){
return clt;
}
public static void main(String[] args) {
ClassLoadTest.getInstance();
System.out.println("a="+a+","+"b="+b);
}
}
其实类的加载主要完成了3件事情:
1:通过类的全限定名来获取该类的二进制字节流
2:把二进制字节流转化为方法区的运行时数据结构
3:在堆上创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
类加载的最终产物就是在堆中的class对象;Class对象封装了类在方法区内的数据结构,并向外提供了访问方法区内数据结构的接口
2.类的加载流程和加载时机
类的加载时机
当应用程序启动的时候,所有的类会被一次性加载吗?估计你早已知道答案,当然不能,因为如果一次性加载,内存资源有限,可能会影响应用程序的正常运行。那类什么时候被加载呢?例如,A a=new A(),一个类真正被加载的时机是在创建对象的时候,才会去执行以上过程,加载类。当我们测试的时候,最先加载拥有main方法的主线程所在类。
类的初始化时机
主动引用(发生类初始化过程)
new一个对象。
调用类的静态成员(除了final常量)和静态方法。
通过反射对类进行调用。
虚拟机启动,main方法所在类被提前初始化。
初始化一个类,如果其父类没有初始化,则先初始化父类。
被动引用(不会发生类的初始化)
当访问一个静态变量时,只有真正声明这个变量的类才会初始化。
(子类调用父类的静态变量,只有父类初始化,子类不初始化)。
通过数组定义类引用,不会触发此类的初始化。 final变量不会触发此类的初始化,因为在编译阶段就存储在常量池中。
再来看一段代码加深一下映像:
[提示:代码看起来不方便,可以在最下面点击阅读原文哈]
public class ClassLoaderProduce {
static int d=3;
static{
System.out.println("我是ClassLoaderProduce类");
}
public static void main(String [] args){ int b=0;
String c="hello";
SimpleClass simpleClass=new SimpleClass();
simpleClass.run();
}
}
class SimpleClass{
static int a=3;
static{
a=100;
System.out.println(a);
}
public SimpleClass(){
System.out.println("对类进行加载!");
}
public void run(){
System.out.println("我要跑跑跑!");
}
}
步骤一:因为main方法启动,所以装载ClassLoaderProduce类,在方法区生成动态数据结构(静态变量、静态方法、常量池、类代码),并且在堆中生成java.lang.Class对象;然后进行链接
步骤二:初始化:把static{}与静态变量合并存放在类构造器当中,对静态变量赋值。 1-5行执行完毕。
3.JVM的类加载器
jvm为了保证代码的安全性,有自己的一套类加载器,来保证类的加载,其实也是大家比较熟悉的类加载机制的双亲委派模型。
以上是关于JVM-类的加载的机制和流程的主要内容,如果未能解决你的问题,请参考以下文章