JAVA 类装载方式,有两种:
隐式装载,程序在运行过程中当碰到通过 new 等方式生成对象时,隐式调用类装载器加载对应的类到 jvm 中。
显式装载,通过 class.forname() 等方法,显式加载需要的类
类加载的动态性体现:
一个应用程序总是由 n 多个类组成,Java 程序启动时,并不是一次把所有的类全部加载后再运行,它总是先把保证程序运行的基础类一次性加载到 jvm 中,其它类等到 jvm 用到的时候再加载,这样的好处是节省了内存的开销,因为 java 最早就是为嵌入式系统而设计的,内存宝贵,这是一种可以理解的机制,而用到时再加载这也是 java 动态性的一种体现。JDK 默认提供了如下几种 ClassLoader
Bootstrp loader
Bootstrp 加载器是用 C ++ 语言写的,它是在 Java 虚拟机启动后初始化的,它主要负责加载 %JAVA_HOME%/jre/lib,-Xbootclasspath 参数指定的路径以及 %JAVA_HOME%/jre/classes 中的类。
ExtClassLoader
Bootstrp loader 加载 ExtClassLoader, 并且将 ExtClassLoader 的父加载器设置为 Bootstrp loader.ExtClassLoader 是用 Java 写的,具体来说就是 sun.misc.Launcher$ExtClassLoader,ExtClassLoader 主要加载 %JAVA_HOME%/jre/lib/ext,此路径下的所有 classes 目录以及 java.ext.dirs 系统变量指定的路径中类库。
AppClassLoader
Bootstrp loader 加载完 ExtClassLoader 后,就会加载 AppClassLoader, 并且将 AppClassLoader 的父加载器指定为 ExtClassLoader。AppClassLoader 也是用 Java 写成的,它的实现类是 sun.misc.Launcher$AppClassLoader,另外我们知道 ClassLoader 中有个 getSystemClassLoader 方法, 此方法返回的正是 AppclassLoader.AppClassLoader 主要负责加载 classpath 所指定的位置的类或者是 jar 文档,它也是 Java 程序默认的类加载器。综上所述,它们之间的关系可以通过下图形象的描述:为什么要有三个类加载器,一方面是分工,各自负责各自的区块,另一方面为了实现委托模型。
类加载器之间是如何协调工作的
前面说了,java 中有三个类加载器,问题就来了,碰到一个类需要加载时,它们之间是如何协调工作的,即 java 是如何区分一个类该由哪个类加载器来完成呢。在这里 java 采用了委托模型机制,这个机制简单来讲,就是“类装载器有载入类的需求时,会先请示其 Parent 使用其搜索路径帮忙载入,如果 Parent 找不到, 那么才由自己依照自己的搜索路径搜索类”下面举一个例子来说明,为了更好的理解,先弄清楚几行代码:
[Java] 纯文本查看 复制代码
?
Public class Test{
Public static void main(String[] arg){ClassLoader c = Test.class.getClassLoader(); // 获取 Test 类的类加载器
System.out.println(c);
ClassLoader c1 = c.getParent(); // 获取 c 这个类加载器的父类加载器
System.out.println(c1);
ClassLoader c2 = c1.getParent();// 获取 c1 这个类加载器的父类加载器
System.out.println(c2);
}
}
运行结果:
[Java] 纯文本查看 复制代码
?
……AppClassLoader……
……ExtClassLoader……
Null
可以看出 Test 是由 AppClassLoader 加载器加载的,AppClassLoader 的 Parent 加载器是 ExtClassLoader, 但是 ExtClassLoader 的 Parent 为 null 是怎么回事呵,朋友们留意的话,前面有提到 Bootstrap Loader 是用 C ++ 语言写的,依 java 的观点来看,逻辑上并不存在 Bootstrap Loader 的类实体,所以在 java 程序代码里试图打印出其内容时,我们就会看到输出为 null。
注:本文转自博客园,版权归博客园所有。
原文链接:https://www.cnblogs.com/doit8791/p/5820037.html