您可能感兴趣的话题:
Java
核心提示:Java的动态特性有两种,一是隐式的;另一种是显示的。
用如下示例测试:
public class AppLoader
{
public static void main(String[] args)
{
String s = System.getProperty("java.class.path");
System.out.println(s);
}
}
/
D:myappclassload>java AppLoader
.;D:myjavaTomcat5.0webappsaxisWEB-INFlibaxis.jar;D:myjavaTomcat5.0weba
ppsaxisWEB-INFlibcommons-logging.jar;D:myjavaTomcat5.0webappsaxisWEB-IN
Flibcommons-discovery.jar;C:oracleora81jdbclibclasses12.zip;D:myjavaJDB
CforSQLserverlibmssqlserver.jar;D:myjavaJDBCforSQLserverlibmsbase.jar;D:m
yjavaJDBCforSQLserverlibmsutil.jar;D:myjavaTomcat5.0commonlibservlet-api
.jar;D:myjavaj2sdk1.4.2_04jrelibt.jar;C:sunappserverlibj2ee.jar;D:myj
avaj2sdk1.4.2_04libjaxp.jar;D:myjavaj2sdk1.4.2_04libsax.jar;
D:myappclassload>java -classpath .;d:myapp AppLoader
.;d:myapp
/
从这个输出结果,我们可以看出,在预设情况下,AppClassLoader 的搜寻路径为”.”(目前所在目
录),如果使用-classpath 选项(与-cp 等效),就可以改变AppClassLoader 的搜寻路径,如果没有
指定-classpath 选项,就会搜寻环境变数CLASSPATH。如果同时有CLASSPATH 的环境设定与
-classpath 选项,则以-classpath 选项的内容为主,CLASSPATH 的环境设定与-classpath 选项两者
的内容不会有加成的效果。
至於ExtClassLoader 也有相同的情形,不过其搜寻路径是参考系统参数java.ext.dirs。
系统参数java.ext.dirs 的内容,会指向java.exe 所选择的JRE 所在位置下的libext 子目录。Java.exe使用的JRE是在系统变量path里指定的,可以通过修改path从而修改ExtCLassLoader的搜寻路径,也可以如下命令参数来更改,
java –Djava.ext.dirs=c:winnt AppLoader //注意 =号两边不能有空格。-D也不能和java分开。
D:myappclassload>java ExtLoader
D:myjavaj2sdk1.4.2_04jrelibext
D:myappclassload>java -Djava.ext.dirs=c:winnt ExtLoader
c:winnt
最後一个类别载入器是Bootstrap Loader , 我们可以经由查询由系统参数sun.boot.class.path 得知Bootstrap Loader 用来搜寻类别的路径。该路径的修改与ExtClassLoader的相同。但修改后不影响Bootstrap的搜寻路径。
在命令列下参数时,使用–classpath / -cp / 环境变数CLASSPATH 来更改AppClassLoader的搜寻路径,或者用–Djava.ext.dirs 来改变ExtClassLoader 的搜寻目录,两者都是有意义的。
可是用–Dsun.boot.class.path 来改变Bootstrap Loader 的搜寻路径是无效。这是因为
AppClassLoader 与ExtClassLoader 都是各自参考这两个系统参数的内容而建立,当您在命令列下
变更这两个系统参数之後, AppClassLoader 与ExtClassLoader 在建立实体的时候会参考这两个系
统参数,因而改变了它们搜寻类别档的路径;而系统参数sun.boot.class.path 则是预设与
Bootstrap Loader 的搜寻路径相同,就算您更改该系统参与,与Bootstrap Loader 完全无关。
改变java.exe所使用的jre会改变Bootstrap Loader的搜寻路径。
Bootstrap Loader的搜寻路径一般如下:
///
D:myjavaj2sdk1.4.2_04jrelibt.jar;D:myjavaj2sdk1.4.2_04jrelibi18n.jar;
D:myjavaj2sdk1.4.2_04jrelibsunrsasign.jar;D:myjavaj2sdk1.4.2_04jrelibj
sse.jar;D:myjavaj2sdk1.4.2_04jrelibjce.jar;D:myjavaj2sdk1.4.2_04jrelib
charsets.jar;D:myjavaj2sdk1.4.2_04jreclasses
///
更重要的是,AppClassLoader 与ExtClassLoader 在整个虚拟机器之中只会存有一份,一旦建
立了,其内部所参考的搜寻路径将不再改变,也就是说,即使我们在程式里利用System.setProperty()
来改变系统参数的内容,仍然无法更动AppClassLoader 与ExtClassLoader 的搜寻路径。因此,执
行时期动态更改搜寻路径的设定是不可能的事情。如果因为特殊需求,有些类别的所在路径并非在
一开始时就能决定,那麽除了产生新的类别载入器来辅助我们载入所需的类别之外,没有其他方法了。
下面我们将看一下载入器的委派模型
所谓的委派模型,用简单的话来讲,就是「类别载入器有载入类别的需求时,会先请示其Parent 使用其搜寻路径帮忙载入,如果Parent 找不到,那麽才由自己依照自己的搜寻路径搜寻类别」。
下面我们看一下小的示例:
public class Test
{
public static void main(String[] args)
{
System.out.println(Test.class.getClassLoader());
TestLib tl = new TestLib();
tl.start();
}
}
public class TestLib
{
public void start()
{
System.out.println(this.getClass().getClassLoader());
}
}
如果这两个类仅放在dos命令提示符的当前目录下,则输出结果如下:
//
sun.misc.Launcher$AppClassLoader@1a0c10f
sun.misc.Launcher$AppClassLoader@1a0c10f
//
如果这两个类同时又放在libextclasses 底下(在我的机器上是:D:myjavaj2sdk1.4.2_04jrelibextclasses,classes没有,需要自己建),输出结果如下:
/
sun.misc.Launcher$ExtClassLoader@e2eec8
sun.misc.Launcher$ExtClassLoader@e2eec8
最后如果在classes下放入这两个类,则输出结果为
/
null
null
如果把classes下的TestLib删去,则输出入下:
//
null
Exception in thread "main" java.lang.NoClassDefFoundError: TestLib
at Test.main(Test.java:7)
//
这是因为Test的classLoader是Bootstrap Loader ,因此TestLib的也默认为是Bootstrap Loader。Bootstrap Loader搜寻路径下的TestLib被删去了,Bootstrap Loader又没有parent,所以提示找不到。
其他的情况可以自己逐个添加或删除文件,然后执行java Test进行测试,察看输出结果。
AppClassLoader 与Bootstrap Loader会搜寻它们所指定的位置(或JAR 档),如果找不到就找不到了,AppClassLoader 与Bootstrap Loader不会递回式地搜寻这些位置下的其他路径或其他没有被指定的JAR 档。反观ExtClassLoader,所参考的系统参数是java.ext.dirs,意思是说,他会搜寻底下的所有JAR 档以及classes 目录,作为其搜寻路径。