基本原理
所有类都由类装载器载入,载入内存中的类对应一个
java.lang.Class
实例。
已被加载的类由该类的类加载器实例与该类的全路径名的组合标识。设有
packagename.A Class
,分别被类加载器
CL1
和
CL2
加载,则系统中有两个不同的
java.lang.Class
实例:
<CL1, packagename.A>
和
<CL2, packagename.A>
。
存在一个
Bootstrap Loader
(以下简称为
BL
),由
C++
写成,负责在虚拟机启动后一次
性加载
Java
基础类库中的所有类。其他的类装载器由
Java
写成,都是
java.lang.ClassLoader
的子类。
除
BL
之外的所有类装载器都有一个
parent
属性,指向其父装载器。查阅
java.lang.ClassLoader
的源码,不难发现类装载器的委托装载方式。
protected
synchronized
Class<?> loadClass(String name,
boolean
resolve)
throws
ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if
(c ==
null
) {
try
{
if
(
parent
!=
null
) {
c =
parent
.loadClass(name,
false
);
}
else
{
c = findBootstrapClass0(name);
}
}
catch
(ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if
(resolve) {
resolveClass(c);
}
return
c;
}
|
对于给定的类名,首先检查自己是否已加载过该类。如果没有,则首先通过父装载器加载(如果
parent==null
,则直接通过
BL
来加载,相当于
BL
是其父装载器)。如果父装载器也无法装载,才真正调用自己的
findClass()
方法来装载。
Java
基础类在
Java
虚拟机启动后由
BL
一次性载入。构成
Java
应用程序的其它类在程序运行过程中由不同类装载器按需通过
loadClass()
方法装载。
Java
程序启动过程中的类装载器
当执行“
java XXX.class
”时,
java.exe
首先找到
JRE
(
Java Runtime Environment
),接着找到位于
JRE
之中的
jvm.dll
,最后载入
jvm.dll
并启动虚拟机。
虚拟机一启动,先做一些初始化动作,如获取系统参数等,然后产生
BL
。
BL
加载
Java
基础类,这些类都存放在
JRE
中的
lib
目录下,可由
System.getProperty(“sun.boot.class.path”)
列出,如:
C:\Program Files\Java\jre1.5.0_09\lib\rt.jar;
C:\Program Files\Java\jre1.5.0_09\lib\i18n.jar;
C:\Program Files\Java\jre1.5.0_09\lib\sunrsasign.jar;
C:\Program Files\Java\jre1.5.0_09\lib\jsse.jar;
C:\Program Files\Java\jre1.5.0_09\lib\jce.jar;
C:\Program Files\Java\jre1.5.0_09\lib\charsets.jar;
C:\Program Files\Java\jre1.5.0_09\classes
|
BL
然后创建
sun.misc.Launcher$ExtClassLoader
(
ExtClassLoader
是定义于
sun.misc.Launcher
之内的内部类,继承自
java.lang.URLClassLoader
)的实例(以下简称
EL
)和
sun.misc.Launcher$AppClassLoader
(
AppClassLoader
是定义于
sun.misc.Launcher
之内的内部类,继承自
URLClassLoader
)的实例(以下简称
AL
),并将
EL
的
parent
属性设置为
null
,
AL
的
parent
属性设置为
EL
。
EL
在程序运行过程中按需加载保存在
JRE
的“
\lib\ext
”目录下的类。该目录可由
System.getProperty(“java.ext.dirs”)
读出,如
C:\Program Files\Java\jre1.5.0_09\lib\ext
|
AL
在程序运行过程中按需加载的类搜索路径则是从系统参数
java.class.path
取出的字符串。
java.class.path
是由我们在执行
java.exe
时,利用
-cp
或
-classpath
或
CLASSPATH
环境变量所决定。我们应用程序用到的非
JRE
提供类的搜索路径一般都配置在
java.class.path
中。
什么时候装载类,由什么类装载器装载
1.
Java
基础类由
BL
在虚拟机启动时一次性载入。
2.
包含
main()
的入口类由
AL
的
loadClass()
方法载入。
3.
由
new
关键字创建一个类的实例。该类由运行时刻包含该
new
语句的类实例的类装载器(
ClassLoader.getCallerClassLoader()
)的
loadClass()
方法载入。
4.
调用
Class.forName()
方法。完整的
forName()
函数版本有一个
ClassLoader
参数,用于指定用什么类装载器来装载指定类。
public
static
Class<?> forName(String name,
boolean
initialize,
ClassLoader loader)
throws
ClassNotFoundException
|
对于
public static Class<?> forName(String className)
版本,是由运行时刻包含该语句的类实例的类装载器(
ClassLoader.getCallerClassLoader()
)的
loadClass()
方法载入。
5.
调用某个
ClassLoader
实例的
loadClass()
方法。通过该
ClassLoader
实例的
loadClass()
方法载入。应用程序可以通过继承
ClassLoader
实现自己的类装载器。
6
.装载一个类时,首先要装载该类的基类及其接口。