Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:
BootStrap, ExtClassLoader, AppClassLoader
类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap。
Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。
示例:
import org.junit.Test; public class ClassLoaderDemo { @Test public void systemLoaderDemo(){ ClassLoader loader=Person.class.getClassLoader(); System.out.println(loader);//AppClassLoader系统类加载器 loader=loader.getParent(); System.out.println(loader);//ExtClassLoader loader=loader.getParent(); System.out.println(loader);//null---BootStrap---不允许我们访问的 } }运行结果:
☆ 类加载器之间的父子关系和管辖范围图:
☆类加载器的委托机制(通过API认识ClassLoader类):
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给其上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?
对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果为ExtClassLoader的原因。
举例:
package cn.hncu; public class LoaderDemo { public static void main(String[] args) { LoaderDemo loader=new LoaderDemo(); System.out.println(loader); } @Override public String toString() { return "yummy5566778899"; } }对于这个简单的例子的输出相信大家是没有争议的。
现在将该类的classpath下的LoaderDemo.class文件所在的根目录(本例中为与src并列的cn文件夹)复制出去,比如放到“d:\\a”文件夹中,接下来打开cmd进入到D盘,输入jar命令符;
图中示例1中Foo.class和Bar.class为需要合并到一起的两个文件,若只有一个文件则只要输入一个就行了。
本例按照图中示例2输入为:jar cvf aa.jar a/ (注意:这里不能输全名,这里只能输a/ 或者a.*其他的无法识别)
然后再d盘根目录下会出现一个aa.jar的文件,将这个文件放到jdk安装目录下的相应位置去,我的电脑上为:
String path="d:\\cn\\hncu\\Person.class"; Class cls=Class.forName(path); System.out.println(cls); Object obj=cls.newInstance(); System.out.println(obj);只要在相应目录下放入相应的.class文件,并且导好了jar包就行了,就可以自动到jdk中相应目录下找到它加载。