先要知道,了解类的加载机制有什么用呢?
首先,可以控制JVM的行为,第二,可以让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性。
类的加载就是把。java文件编译成。class文件,然后加载到内存中的过程。
说到类加载,就不得不说配置jdk环境变量时用到的classpath了,通常我们的配置顺序是:.;D:\Java\jdk6\lib\dt.jar;D:\Java\jdk6\lib\tools.jar,如果将这个顺序改一下,那么加载的顺序也会发生变化。
JAVA中有三种类加载器:
1、Bootstrap Loader(启动类加载器):加载System.getProperty("sun.boot.class.path")所指定的路径或jar。
2、Extended Loader(标准扩展类加载器ExtClassLoader):加载System.getProperty("java.ext.dirs")所指定的路径或jar。在使用Java运行程序时,也可以指定其搜索路径,例如:java -Djava.ext.dirs=d:/projects/testproj/classes HelloWorld
3、AppClass Loader(系统类加载器AppClassLoader):加载System.getProperty("java.class.path")所指定的路径或jar。在使用Java运行程序时,也可以加上-cp来覆盖原有的Classpath设置,例如: java -cp ./lavasoft/classes HelloWorld
ExtClassLoader和AppClassLoader在JVM启动后,会在JVM中保存一份,并且在程序运行中无法改变其搜索路径。如果想在运行时从其他搜索路径加载类,就要产生新的类加载器。
JAVA加载时会从上到下依次加载,需要注意的是Bootstrap Loader(启动类加载器)是最顶级的类加载器了,其父加载器为null.不过ext和boot也不是父子关系。因为boot是C实现的。
可以看这样一个例子:
public static void main(String[] args){
System.out.println(AAA.class.getName());
System.out.println(AAA.class.getClassLoader());
System.out.println(AAA.class.getClassLoader().getParent());
System.out.println(AAA.class.getClassLoader().getParent().getParent());
System.out.println(String.class.getClassLoader());
}
输出结果为:
com.AAA
sun.misc.Launcher$AppClassLoader@18efd7c
sun.misc.Launcher$ExtClassLoader@a40f0e
null
null
类的加载
类加载有三种方式:
1、命令行启动应用时候由JVM初始化加载
2、通过Class.forName()方法动态加载
3、通过ClassLoader.loadClass()方法动态加载
三种方式区别比较大,看个例子就明白了:
public
class HelloWorld {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader loader = HelloWorld. class.getClassLoader();
System.out.println(loader);
//使用ClassLoader.loadClass()来加载类,不会执行初始化块
loader.loadClass( "Test2");
//使用Class.forName()来加载类,默认会执行初始化块
// Class.forName("Test2");
//使用Class.forName()来加载类,并指定ClassLoader,初始化时不执行静态块
// Class.forName("Test2", false, loader);
}
}
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader loader = HelloWorld. class.getClassLoader();
System.out.println(loader);
//使用ClassLoader.loadClass()来加载类,不会执行初始化块
loader.loadClass( "Test2");
//使用Class.forName()来加载类,默认会执行初始化块
// Class.forName("Test2");
//使用Class.forName()来加载类,并指定ClassLoader,初始化时不执行静态块
// Class.forName("Test2", false, loader);
}
}
public
class Test2 {
static {
System.out.println( "静态初始化块执行了!");
}
}
static {
System.out.println( "静态初始化块执行了!");
}
}
分别切换加载方式,会有不同的输出结果。
有关ClassLoader还有很重要一点:
同一个ClassLoader加载的类文件,只有一个Class实例。但是,如果同一个类文件被不同的ClassLoader载入,则会有两份不同的ClassLoader实例(前提是着两个类加载器不能用相同的父类加载器)。