您的位置:首页 > 编程语言 > Java开发

Java类加载机制

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

类加载启动过程如下:

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

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文件。而我们自定义的类只有在使用的时候才会加载。

类的加载也可以分为隐式加载和显式加载:

隐式加载:程序中使用new关键字,JRE在执行到new关键字时候会把对应的类加载到内存中,JRE在后台自动的帮助用户加载;
显式加载:通过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加载,这个前提是有两个加载器且它们的父加载器不是同一个。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: