深入理解虚拟机类加载机制

来源:互联网 发布:数据库应用课程 编辑:程序博客网 时间:2024/05/22 13:39

昨天整理了有关Java单例模式的知识点,里面提及Java类加载机制,今天对Java类加载机制做一个总结。内容有本人学习整理而来。

一、类加载机制概述

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。——《深入理解Java虚拟机》

二、类加载机制过程

当在命令行执行:java HelloWorld 命令的时候,JVM会将HelloWorld.class加载到内存中,并形成一个Class的对象HelloWorld.class。
其中的过程就是类加载过程:
  1. 寻找jre目录,寻找jvm.dll,并初始化JVM;
  2. 产生一个Bootstrap Loader(启动类加载器);
  3. Bootstrap Loader自动加载Extended Loader(标准扩展类加载器),并将其父Loader设为Bootstrap Loader。
  4. Bootstrap Loader自动加载AppClass Loader(系统类加载器),并将其父Loader设为Extended Loader。
  5. 最后由AppClass Loader加载HelloWorld类。

三、类加载器

  1. Bootstrap ClassLoader(启动类加载器) : 将存放于<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar 名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接引用
  2. Extension ClassLoader(标准扩展类加载器ExtClassLoader) : 将<JAVA_HOME>\lib\ext目录下的,或者被java.ext.dirs系统变量所指定的路径中的所有类库加载。开发者可以直接使用扩展类加载器。
  3.  Application ClassLoader (系统类加载器AppClassLoader): 负责加载用户类路径(ClassPath)上所指定的类库,开发者可直接使用。
  4.  ExtClassLoader和AppClassLoader在JVM启动后,会在JVM中保存一份,并且在程序运行中无法改变其搜索路径。如果想在运行时从其他搜索路径加载类,就要产生新的类加载器。

类加载器特点

  1. 运行一个程序时,总是由AppClass Loader(系统类加载器)开始加载指定的类。
  2. 在加载类时,每个类加载器会将加载任务上交给其父,如果其父找不到,再由自己去加载。
  3. Bootstrap Loader(启动类加载器)是最顶级的类加载器了,其父加载器为null.

-------------------------------------上篇博文提及到的单例模式面试题解析-------------------------------------------------------

class SingleTon {private static SingleTon singleTon = new SingleTon();public static int count1;public static int count2 = 0;private SingleTon() {count1++;count2++;}public static SingleTon getInstance() {return singleTon;}}public class Test {public static void main(String[] args) {SingleTon singleTon = SingleTon.getInstance();System.out.println("count1=" + singleTon.count1);System.out.println("count2=" + singleTon.count2);}}

错误答案

count1=1

count2=1

 正确答案

count1=1

count2=0


首先得清楚JVM对一个类的字节码class文件是如果装载到内存中然后被虚拟机执行的。

1.加载:查找并加载类的二进制数据
2.连接
   2.1  确保被加载类的正确性
   2.2  为类的静态变量分配内存,并将其初始化为默认值
   2.3  把类中的符号引用转换为直接引用

3.初始化:为类的静态变量赋予正确的初始值


分析:
  1. SingleTon singleTon = SingleTon.getInstance();调用了类的SingleTon调用了类的静态方法,触发类的初始化
  2. 类加载的时候在准备过程中为类的静态变量分配内存并初始化默认值 singleton=null count1=0,count2=0
  3. 类初始化,为类的静态变量赋值和执行静态代码快。singleton赋值为new SingleTon()调用类的构造方法
  4. 调用类的构造方法后count1=1;count2=1
  5. 继续为count1与count2赋值,此时count1没有赋值操作,所有count1为1,但是count2执行赋值操作就变为0 



0 0
原创粉丝点击