Java类加载机制

        在JVM里面有多个类加载器,每个类加载器负责加载特定位置的类。例如,Bootstrap类加载负责加载jre/lib/rt.jar中的类(平时用的类都在此包中),Launcher类中的Launcher$ExtClassLoader(标准扩展类加载器)负责加载jre/lib/ext/*.jar中的类,Launcher$AppClassLoader(系统类加载器)负责加载classpath指定目录的jar中的类。

  • 类加载启动过程如下:
  1. 执行java.exe找到jar,再找到jre/bin/server/jvm.dll,开始初始化JAM;
  2. 产生一个Bootstrap Loader(最顶级的类加载器,其父加载器为null,是用c语言实现的,也称为靴带机制)加载环境变量sun.boot.class.path所指定的路径或jar;
  3. Bootstrap Loader自动加载ExtClassLoader,加载环境变量java.ext.dirs所指定的路径或jar,并将其父加载器设为Bootstrap Loader;
  4. Bootstrap Loader自动加载AppClassLoader,加载环境变量java.ext.dirs所指定的路径或jar,在linux系统中可以使用cp命令去覆盖此路径,并将其父加载器设为ExtClassLoader;
  5. 最后由AppClassLoader加载classpath下面的类;
  6. 在加载类时,每个类加载器将加载任务交其父类,如果父类找不到再由自己去加载;

       ExtClassLoader和AppClassLoader都是以静态类的形式存在的,并且都是由Bootstrap Loader加载的,但ExtClassLoader是AppClassLoader的父类,所以父类parent跟是由谁加载的没有关系。 ExtClassLoader和AppClassLoader在JVM中启动后,会在JVM中保存一份,并且在程序运行中无法改变其搜索路径,如果想在运行时从其它搜索路径加载类,就要产生新的加载器。

   public class HelloWorld { 
        public static void main(String[] args) { 
                HelloWorld hello = new HelloWorld(); 
                Class c = hello.getClass(); 
                ClassLoader loader = c.getClassLoader(); 
                System.out.println(loader); 
                System.out.println(loader.getParent()); 
                System.out.println(loader.getParent().getParent()); 
        } 
   }
       打印结果:
   sun.misc.Launcher$AppClassLoader@sdes03 
   sun.misc.Launcher$ExtClassLoader@fdfe2d 
   null

        从结果中看打印出Launcher$ExtClassLoader的父类为null,而不是Bootstrap Loader,这是因为Bootstrap Loader是用C语言开发出来的,在所有的jar包都找不到该类,就用null来代替。

       类的加载可以分为预先加载和按需加载:java运行中所需要的基本类都采用预先加载的方法,将类都加载到内在中,这些类主要是rt.java文件里面所有的.class文件。而我们自定义的类只有在使用的时候才会加载。

  • 类的加载也可以分为隐式加载和显式加载:
  1. 隐式加载:程序中使用new关键字,JRE在执行到new关键字时候会把对应的类加载到内存中,JRE在后台自动的帮助用户加载;
  2. 显式加载:通过Class.forName()方法动态加载,ClassLoader.loadClass()方法动态加载;

       调用Class.forName方式实现动态加载:

       
 
       参数说明:
              className - 所需类的完全限定名
              initialize - 是否必须初始化类(静态代码块的初始化)
              loader - 用于加载类的类加载器
       forName(String className)和forName(String className, boolean initialize, ClassLoader loader)最终都是调用forName0方法,forName0定义如下:

   private static native Class forName0(String name, boolean initialize,ClassLoader loader)throws ClassNotFoundException;

       从中可以看出,是否初始化类是有一个开关的,即是否运行静态代码块。如果将将第二个参数initialize设置为false,那么这时只会加载而不会初始化静态代码块,只有实例化这个类的时候(创建该类的对象),静态代码块才会开始初始化,静态代码块在第一次实例化的时候开始初始化。

  • 自定义类加载器

       

        同一个ClassLoader加载的类文件,在内存中只有一个class实例,但是也会有同一个类文件被不同的ClassLoader加载,这个前提是有两个加载器且它们的父加载器不是同一个。

        


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值