JAVA类加载机制

来源:互联网 发布:网络教育网上报名 编辑:程序博客网 时间:2024/06/04 01:20

一、JVM类加载过程

   类被加载到JVM中,一共会经历五个阶段:加载、验证、准备、解析、初始化(验证、准备、解析统称为连接阶段)

   

   加载:在加载阶段主要做了三件事情:

    ①获取.class文件的二进制 ;

    ②将类信息、静态变量、字节码、常量池等这些.class文件中的内容放入到方法区中;

    ③在内存中生成一个代表这个.class文件的class对象,作为方法区这个类的各种数据访问入口

   连接:在连接过程中主要分三步:

   ①验证:验证阶段主要是为了确保.class文件的字节流中所包含的各种信息是符合JVM规范的,并不会威胁到虚拟机的安全;

   ②准备:准备阶段主要为类变量分配存储空间,这些变量所使用的内存都将在方法区中分配,要注意一下:这里的变量仅仅指的是被static修饰的类变量,而不是实例变量,实例变量将会在对象实例化的时候随着对象一起分配在Java堆中;

   ③解析:解析阶段主要是将虚拟机常量池中的符号引用转换为直接引用的过程;

    初始化:在初始化过程中,如果执行的是静态变量,则将类中所有被static关键字修饰的变量赋予初始值;如果执行的是static代码块,那么在初始化阶段JVM就会执行static代码块中定义的所有操作,只有在类首次进行初始化的时候,才会进行初始化。

 类初始化的步骤:

1、如果这个类没有被加载和连接的话,那就先进行加载和连接。

2、如果这个类有父类,并且这个父类没有被初始化,则先初始化父类

3、假如类中存在初始化语句,依次执行初始化语句。

二、类加载器

  类加载器的任务是将一个类的二进制字节流读取到JVM中,然后转换为一个与目标相对应的Java.lang.Class对象实例,该实例中包含了类的所有信息。

  

  启动类加载器(BootStrap ClassLoader),负责加载存放在JDK/jre/lib(JDK表示JDK的安装目录或者被-Xbootclasspath参数所制定的路径中的能被虚拟机识别的类库),所有以java.*开头的文件均被BootStrap ClassLoader加载,它底层是用c++实现(仅限于hotspot虚拟机),是虚拟机自身的一部分,并且无法被Java程序直接使用。

  扩展类加载器(Extension ClassLoader),负责加载存放在JDK/jre/lib/ext目录中的内容,所有以javax.*开头的类均被Extension ClassLoader加载,开发者可以直接使用。

  应用程序类加载器(Application ClassLoader),负责加载用户类路径(classpath)所指定的类,是我们经常使用的类加载器。

  类加载有三种方式:

 ①命令行启动应用时由JVM初始化加载;

 ②通过Class类的静态方法forName()动态加载,如Class.forName("com.example.test.Text");

 ③通过ClassLoader.loadClass()方法动态加载,如

   class Test_{

static{
System.out.println("静态代码块被执行!");
       }
   }
   public class Text_723 {

public static void main(String[] args) throws ClassNotFoundException {
// TODO Auto-generated method stub
ClassLoader loader = Text_723.class.getClassLoader();
System.out.println(loader);
loader.loadClass("com.example.test.Test_");
}
  }

三、双亲委托模型(约定类加载器的加载机制)

        当一个类加载器收到一个类加载任务时,不会展开立即加载,而是将加载任务委托给它的父类加载器去执行,每一层的类都采取相同的方式,直至委托给最顶层的启动类加载器为止。如果父类加载器无法加载委托给它的类,便将加载任务退回给下一级类加载器去执行加载。

       使用双亲委托模型魔性的好处是:Java类随着它的类加载器一起具备了一种带有优先级的层次关系。如:类java.lang.Object,无论哪一个类要加载这个类,最终都是委托给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种加载环境中都是同一个类。相反,如果没有使用双亲委托模型,由各个类自行去加载的话,如果用户自己编写了一个java.lang.Object的类,并放在程序的classpath中,那系统将会出现多个不同的Object类,Java类型体系中最基础的行为也无法保证,应用程序将会变得一片 混乱。使用双亲委托模型,如果自己编写了一个与类库中类重名的Java类,将会发现可以正常编译,但永远无法被加载运行。


原创粉丝点击