欢迎大家来到测试人生,在你休息的时候你可以畅所欲言,空间里也许有些资料可以帮助到你,来吧,朋友,测试人生欢迎你!!!!

【转贴】理解Java ClassLoader机制

上一篇 / 下一篇  2008-06-24 12:22:39 / 个人分类:JAVA类

51Testing软件测试网 N;G"ai YQ U3Y

原文链接:http://www.sharecenter.net/archiver/tid-109152.html

vQP&_%K.iN051Testing软件测试网G"A/K H@5F8Ti3\

当JVM(Java虚拟机)启动时,会形成由三个类加载器组成的初始类加载器层次结构:51Testing软件测试网've,e oqA

Kz|9_xP p7\0       bootstrap classloader
_"`wO'lhe`0                |51Testing软件测试网(y:A&`x$a.HI(c
       extension classloader
#dXq"| |m3L0                |51Testing软件测试网HiBn!|!w,U
       system classloader51Testing软件测试网V%z'c0R"e7Qz
51Testing软件测试网!T-]hk*E
bootstrap classloader -引导(也称为原始)类加载器,它负责加载Java的核心类。在Sun的JVM中,在执行java的命令中使用-Xbootclasspath选项或使用- D选项指定sun.boot.class.path系统属性值可以指定附加的类。这个加载器的是非常特殊的,它实际上不是 java.lang.ClassLoader的子类,而是由JVM自身实现的。大家可以通过执行以下代码来获得bootstrap classloader加载了那些核心类库:
ou/Cs0Fl3No4@0   URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();51Testing软件测试网^| V n|)p
   for (int i = 0; i < urls.length; i++) {51Testing软件测试网{Y/v6\8S9QC@5H]
     System.out.println(urls.toExternalform());51Testing软件测试网&E b:{XH+K
   }
*dN-ty W:?m(w)D0在我的计算机上的结果为:51Testing软件测试网+f![ `/P5]]H
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/dom.jar51Testing软件测试网`2S&o%qO i
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/sax.jar
6O1b/}WgI@0文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xalan-2.3.1.jar
[ G"U.yq2R0文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xercesImpl-2.0.0.jar
]3e? O f~/Q$v LMti0文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xml-apis.jar
a7r1l ?{1r`4mPAb0文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xsltc.jar51Testing软件测试网^K#Vn$@}
文件:/C:/j2sdk1.4.1_01/jre/lib/rt.jar
*[/Dy+[:_c0文件:/C:/j2sdk1.4.1_01/jre/lib/i18n.jar
"j9s9Q*` d2~ LP!r)l0文件:/C:/j2sdk1.4.1_01/jre/lib/sunrsasign.jar
,V3DgN^0b-jG jb0文件:/C:/j2sdk1.4.1_01/jre/lib/jsse.jar51Testing软件测试网C QeR1I%h(j0o
文件:/C:/j2sdk1.4.1_01/jre/lib/jce.jar
7y|G$IH2E,|0文件:/C:/j2sdk1.4.1_01/jre/lib/charsets.jar
YK5m-\k6r0文件:/C:/j2sdk1.4.1_01/jre/classes51Testing软件测试网J_aK&S @[j!z`"S s
这时大家知道了为什么我们不需要在系统属性CLASSPATH中指定这些类库了吧,因为JVM在启动的时候就自动加载它们了。51Testing软件测试网/cz X] bE!h
51Testing软件测试网&?U\*pb5A O(|
extension classloader -扩展类加载器,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中JAR的类包。这为引入除Java核心类以外的新功能提供了一个标准机制。因为默认的扩展目录对所有从同一个JRE中启动的JVM都是通用的,所以放入这个目录的 JAR类包对所有的JVM和system classloader都是可见的。在这个实例上调用方法getParent()总是返回空值null,因为引导加载器bootstrap classloader不是一个真正的ClassLoader实例。所以当大家执行以下代码时:51Testing软件测试网/s pq)sEAG"p
   System.out.println(System.getProperty("java.ext.dirs"));51Testing软件测试网b(F0TK+y(Ht ?
   ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
0\tLO"|-[S3v0   System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());51Testing软件测试网D1Y&AH"U:Q d x
结果为:
U H RG+Q%YX0C:\j2sdk1.4.1_01\jre\lib\ext51Testing软件测试网^1fN0fud"u3L
the parent of extension classloader : null51Testing软件测试网Mw{*q0N8` p
extension classloader是system classloader的parent,而bootstrap classloader是extension classloader的parent,但它不是一个实际的classloader,所以为null。
vj%ZK3sw0
O,~:l8IF` V1k0system classloader -系统(也称为应用)类加载器,它负责在JVM被启动时,加载来自在命令java中的-classpath或者java.class.path系统属性或者 CLASSPATH*作系统属性所指定的JAR类包和类路径。总能通过静态方法ClassLoader.getSystemClassLoader()找到该类加载器。如果没有特别指定,则用户自定义的任何类加载器都将该类加载器作为它的父加载器。执行以下代码即可获得:51Testing软件测试网-j Zba,W cMS
   System.out.println(System.getProperty("java.class.path"));
1G|9x)ynLC0输出结果则为用户在系统属性里面设置的CLASSPATH。51Testing软件测试网t*Gc(~'m*?Y r
classloader 加载类用的是全盘负责委托机制。所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有 Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入;委托机制则是先让parent(父)类加载器 (而不是super,它与parent classloader类不是继承关系)寻找,只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制,也就是如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是必须重新启动JVM才能生效的原因。
$l,Ka%J!YwV0WbC051Testing软件测试网{:R b8e#P8M o&W
51Testing软件测试网%ID#vbt6]eq1cc
每个ClassLoader加载Class的过程是:51Testing软件测试网2b_'f^3F
1.检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2
y BdE-bNJqrV02.如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到451Testing软件测试网t[-gf2S} P
3.请求parent classloader载入,如果成功到8,不成功到5
-RKMvY/O04.请求jvm从bootstrap classloader中载入,如果成功到851Testing软件测试网n8Um+A|aV
5.寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到7.51Testing软件测试网N8d|F2@ P;I
6.从文件中载入Class,到8.51Testing软件测试网!Wr:ed.x3A
7.抛出ClassNotFoundException.
ui/cBi08.返回Class.
Q&i6n8S({0L0
5Fv4Q:USd`0其中5.6步我们可以通过覆盖ClassLoader的findClass方法来实现自己的载入策略。甚至覆盖loadClass方法来实现自己的载入过程。51Testing软件测试网V^ s!G8y

-[6s:x[QKL0类加载器的顺序是:51Testing软件测试网\)gF9^9P(d)B\"?Gh
先是bootstrap classloader,然后是extension classloader,最后才是system classloader。大家会发现加载的Class越是重要的越在靠前面。这样做的原因是出于安全性的考虑,试想如果system classloader“亲自”加载了一个具有破坏性的“java.lang.System”类的后果吧。这种委托机制保证了用户即使具有一个这样的类,也把它加入到了类路径中,但是它永远不会被载入,因为这个类总是由bootstrap classloader来加载的。大家可以执行一下以下的代码:
8l fJUNRE,Zr0   System.out.println(System.class.getClassLoader());
4Xbq\oA0将会看到结果是null,这就表明java.lang.System是由bootstrap classloader加载的,因为bootstrap classloader不是一个真正的ClassLoader实例,而是由JVM实现的,正如前面已经说过的。51Testing软件测试网a+J9}'k9Ey}X
51Testing软件测试网S!mR A+i`s
下面就让我们来看看JVM是如何来为我们来建立类加载器的结构的:51Testing软件测试网wh&\ U0_\+X
sun.misc.Launcher,顾名思义,当你执行java命令的时候,JVM会先使用bootstrap classloader载入并初始化一个Launcher,执行下来代码:
ZX^:su EF?`0  System.out.println("the Launcher's classloader is "+sun.misc.Launcher.getLauncher().getClass().getClassLoader());51Testing软件测试网o A@s[?,^ c
结果为:51Testing软件测试网&T'e!t+Mu+[*R!Z
  the Launcher's classloader is null (因为是用bootstrap classloader加载,所以class loader为null)51Testing软件测试网4y Rj;c7n$w_5WA
Launcher 会根据系统和命令设定初始化好class loader结构,JVM就用它来获得extension classloader和system classloader,并载入所有的需要载入的Class,最后执行java命令指定的带有静态的main方法的Class。extension classloader实际上是sun.misc.Launcher$ExtClassLoader类的一个实例,system classloader实际上是sun.misc.Launcher$AppClassLoader类的一个实例。并且都是 java.net.URLClassLoader的子类。51Testing软件测试网 k0` ?hC:xdbb

CF o#_Q"U(kp!a@LK0让我们来看看Launcher初试化的过程的部分代码。
-}qEI fE0
p_-S_.YixX0Launcher的部分代码:
*X/Q$h:?.qo$qJ0public class Launcher  {
U]{c,t0   public Launcher() {
b(V/|'dTV0       ExtClassLoader extclassloader;
^+xlM0hh\0       try {51Testing软件测试网1];i ]/f,a,SJw)~J
           //初始化extension classloader51Testing软件测试网~R,U}C'y
           extclassloader = ExtClassLoader.getExtClassLoader();51Testing软件测试网&S;CRX L8^5Ro {R
       } catch(IOException ioexception) {51Testing软件测试网{&}"b8K|:^
           throw new InternalError("Could not create extension class loader");51Testing软件测试网z.| [5m8u`~#d9Y
       }
1^-`5dhDp0       try {
StXnm4MSS0           //初始化system classloader,parent是extension classloader51Testing软件测试网x'm!X1C*A.E\@
           loader = AppClassLoader.getAppClassLoader(extclassloader);51Testing软件测试网fa%X/z m*|j
       } catch(IOException ioexception1) {
,M&F#t)|9n3TH1m0           throw new InternalError("Could not create application class loader");51Testing软件测试网 F3K2\K](E7H
       }51Testing软件测试网7A$M`s?9qaL9U$_
       //将system classloader设置成当前线程的context classloader(将在后面加以介绍)
O:QY hn{0       Thread.currentThread().setContextClassLoader(loader);
I)fZbI0       ......51Testing软件测试网8M?7v-F&\)]4K
   }51Testing软件测试网G-L5T4f"y[ lt
   public ClassLoader getClassLoader() {51Testing软件测试网^"r3K P/l"q}2_A
       //返回system classloader
i5CP3G*x0       return loader;51Testing软件测试网%t3Y}$~-Ow
   }51Testing软件测试网fMSh l
}51Testing软件测试网6Q0GaU?{
51Testing软件测试网G T'fcqN
extension classloader的部分代码:
TkCg\,RN-[o"B5Au0static class Launcher$ExtClassLoader extends URLClassLoader {
zMS:s?h j051Testing软件测试网6m\.] iX7} A
   public static Launcher$ExtClassLoader getExtClassLoader()51Testing软件测试网OB}o__:}
       throws IOException
h'uf"R xg0   {
2?eTv5j0       File afile[] = getExtDirs();51Testing软件测试网x,zbguX2z d
       return (Launcher$ExtClassLoader)AccessController.doPrivileged(new Launcher$1(afile));
d} Y[*no-Dw u0   }51Testing软件测试网ZE)Y/K2Qs2~,e
  private static File[] getExtDirs() {
{&TxA0I^fJqEQ0       //获得系统属性“java.ext.dirs”
k5u]k [D0       String s = System.getProperty("java.ext.dirs");
}"B-@6s |4]zY0       File afile[];
|ls;|Y,}E E:jF0       if(s != null) {51Testing软件测试网:iWzU\I
           StringTokenizer stringtokenizer = new StringTokenizer(s, File.pathSeparator);51Testing软件测试网W,tG J5]h
           int i = stringtokenizer.countTokens();51Testing软件测试网Av$T#G.p|eI
           afile = new File;
(lR dw~ ]Y.nn0           for(int j = 0; j < i; j++)
w{N n'aY0               afile[j] = new File(stringtokenizer.nextToken());51Testing软件测试网!_(Sf'] KeV

"xg-Tr*n^_0       } else {51Testing软件测试网$f ggY-mo)_dl
           afile = new File[0];
:Vbn8PnF/s0       }51Testing软件测试网4i*dU2?-YgS
       return afile;51Testing软件测试网;Arn!P9E vw LK,E+_"z
   }
\.K[L#U0}51Testing软件测试网hK:U1MYyzG+O
51Testing软件测试网Ah5TZan3H
system classloader的部分代码:
E1s3nBt!|-l6_l0static class Launcher$AppClassLoader extends URLClassLoader
%w,j7X` T#jLN1H0{
Ce\ D Dci0
;VP0v#A{o p0   public static ClassLoader getAppClassLoader(ClassLoader classloader)
;{tS O:T#t0       throws IOException
? e[ _ y6J ]0   {
3hD-xb9`!|8Jm$Y p1b0       //获得系统属性“java.class.path”51Testing软件测试网/Wt z&PZ X2ca+z6R
       String s = System.getProperty("java.class.path");
b1m4g,Pi(`%Q5B:G-U0       File afile[] = s != null ? Launcher.access$200(s) : new File[0];51Testing软件测试网q C0f g-O6a$GFp0f
       return (Launcher$AppClassLoader)AccessController.doPrivileged(new Launcher$2(s, afile, classloader));51Testing软件测试网3r+l J'R:N x+~
   }
!y(qJJQWa/y(ENa6I0}
9s5x+OT,B;Q yt051Testing软件测试网(^X2H9m+UJ WLV
看了源代码大家就清楚了吧,extension classloader是使用系统属性“java.ext.dirs”设置类搜索路径的,并且没有parent。system classloader是使用系统属性“java.class.path”设置类搜索路径的,并且有一个parent classloader。Launcher初始化extension classloader,system classloader,并将system classloader设置成为context classloader,但是仅仅返回system classloader给JVM。
c]\h7x#~ [/a {-I051Testing软件测试网-tQB+Wg[fE
  这里怎么又出来一个context classloader呢?它有什么用呢?我们在建立一个线程Thread的时候,可以为这个线程通过setContextClassLoader方法来指定一个合适的classloader作为这个线程的context classloader,当此线程运行的时候,我们可以通过getContextClassLoader方法来获得此context classloader,就可以用它来载入我们所需要的Class。默认的是system classloader。利用这个特性,我们可以“打破”classloader委托机制了,父classloader可以获得当前线程的context classloader,而这个context classloader可以是它的子classloader或者其他的classloader,那么父classloader就可以从其获得所需的 Class,这就打破了只能向父classloader请求的限制了。这个机制可以满足当我们的classpath是在运行时才确定,并由定制的 classloader加载的时候,由system classloader(即在jvm classpath中)加载的class可以通过context classloader获得定制的classloader并加载入特定的class(通常是抽象类和接口,定制的classloader中是其实现),例如web应用中的servlet就是用这种机制加载的.51Testing软件测试网H7D BBPdt
51Testing软件测试网.?"gj6o5ev^v6?9H r.o6l
51Testing软件测试网@)A*O |N
好了,现在我们了解了classloader的结构和工作原理,那么我们如何实现在运行时的动态载入和更新呢?只要我们能够动态改变类搜索路径和清除classloader的cache中已经载入的Class就行了,有两个方案,一是我们继承一个classloader,覆盖loadclass方法,动态的寻找Class文件并使用defineClass方法来;另一个则非常简单实用,只要重新使用一个新的类搜索路径来new一个classloader就行了,这样即更新了类搜索路径以便来载入新的Class,也重新生成了一个空白的cache(当然,类搜索路径不一定必须更改)。噢,太好了,我们几乎不用做什么工作,java.netURLClassLoader正是一个符合我们要求的classloader!我们可以直接使用或者继承它就可以了!
nM.Pf|py051Testing软件测试网H/o(K.vo%d?2@
这是j2se1.4 API的doc中URLClassLoader的两个构造器的描述:
kK r4l.ReJ0URLClassLoader(URL[] urls)
&s#s"Ct5G Hme+\"H0         Constructs a new URLClassLoader for the specified URLs using the default delegation parent ClassLoader.51Testing软件测试网'|-? G[,Qr1Z5a
URLClassLoader(URL[] urls, ClassLoader parent)51Testing软件测试网 CW oRp
         Constructs a new URLClassLoader for the given URLs.
9v9[7Sj:C4VR!^0其中URL[] urls就是我们要设置的类搜索路径,parent就是这个classloader的parent classloader,默认的是system classloader。51Testing软件测试网B5qryo Y
51Testing软件测试网L#|c*Q:}D;SwY#Z3L

y k+n7dj;frw0好,现在我们能够动态的载入Class了,这样我们就可以利用newInstance方法来获得一个Object。但我们如何将此Object造型呢?可以将此Object造型成它本身的Class吗?
:A6gQ:D5V0
}lW9?;j? u0首先让我们来分析一下java源文件的编译,运行吧!javac命令是调用“JAVA_HOME/lib/tools.jar”中的“com.sun.tools.javac.Main”的compile方法来编译:
tq5zg|] Zzf-v051Testing软件测试网r,L,XRS/i p8Ok
   public static int compile(String as[]);51Testing软件测试网T:D(BO#Q7hf&v
51Testing软件测试网Q|$OJ$D0H6R\
   public static int compile(String as[], PrintWriter printwriter);
)B:N$]{.QO"KPf0
Y0[7v5}1~8k8[` b4L0返回0表示编译成功,字符串数组as则是我们用javac命令编译时的参数,以空格划分。例如:
BVr Eq6\ex0javac -classpath c:\foo\bar.jar;. -d c:\ c:\Some.java
vod5Yz3W0则字符串数组as为{"-classpath","c:\\foo\\bar.jar;.","-d","c:\\","c:\\Some.java"},如果带有PrintWriter参数,则会把编译信息出到这个指定的printWriter中。默认的输出是System.err。51Testing软件测试网8}c8X2Y{2PvuE E

FD6L5i3fmI0其中 Main是由JVM使用Launcher初始化的system classloader载入的,根据全盘负责原则,编译器在解析这个java源文件时所发现的它所依赖和引用的所有Class也将由system classloader载入,如果system classloader不能载入某个Class时,编译器将抛出一个“cannot resolve symbol”错误。51Testing软件测试网$]6e |P,u c!C4Z)j

7I*~9mJ:j0所以首先编译就通不过,也就是编译器无法编译一个引用了不在CLASSPATH中的未知Class的java源文件,而由于拼写错误或者没有把所需类库放到CLASSPATH中,大家一定经常看到这个“cannot resolve symbol”这个编译错误吧!
$W,i.M9oZjY`0
b CAYf)wy0其次,就是我们把这个Class放到编译路径中,成功的进行了编译,然后在运行的时候不把它放入到CLASSPATH中而利用我们自己的 classloader来动态载入这个Class,这时候也会出现“java.lang.NoClassDefFoundError”的违例,为什么呢?
a y6Y`2\051Testing软件测试网%iy7p^'Kn
我们再来分析一下,首先调用这个造型语句的可执行的Class一定是由JVM使用Launcher初始化的system classloader载入的,根据全盘负责原则,当我们进行造型的时候,JVM也会使用system classloader来尝试载入这个Class来对实例进行造型,自然在system classloader寻找不到这个Class时就会抛出“java.lang.NoClassDefFoundError”的违例。
Wd8J6_0a!h051Testing软件测试网;qfG{!d(k
OK,现在让我们来总结一下,java文件的编译和Class的载入执行,都是使用Launcher初始化的system classloader作为类载入器的,我们无法动态的改变system classloader,更无法让JVM使用我们自己的classloader来替换system classloader,根据全盘负责原则,就限制了编译和运行时,我们无法直接显式的使用一个system classloader寻找不到的Class,即我们只能使用Java核心类库,扩展类库和CLASSPATH中的类库中的Class。51Testing软件测试网jKG6yC9B&P R
51Testing软件测试网F&K+dpg
还不死心!再尝试一下这种情况,我们把这个Class也放入到CLASSPATH中,让system classloader能够识别和载入。然后我们通过自己的classloader来从指定的class文件中载入这个Class(不能够委托 parent载入,因为这样会被system classloader从CLASSPATH中将其载入),然后实例化一个Object,并造型成这个Class,这样JVM也识别这个Class(因为 system classloader能够定位和载入这个Class从CLASSPATH中),载入的也不是CLASSPATH中的这个Class,而是从 CLASSPATH外动态载入的,这样总行了吧!十分不幸的是,这时会出现“java.lang.ClassCastException”违例。51Testing软件测试网-J4W3z B\/U&A

$a6?:b$T9{3E N)Y0为什么呢?我们也来分析一下,不错,我们虽然从CLASSPATH外使用我们自己的classloader动态载入了这个Class,但将它的实例造型的时候是JVM会使用system classloader来再次载入这个Class,并尝试将使用我们的自己的classloader载入的Class的一个实例造型为system classloader载入的这个Class(另外的一个)。大家发现什么问题了吗?也就是我们尝试将从一个classloader载入的Class的一个实例造型为另外一个classloader载入的Class,虽然这两个Class的名字一样,甚至是从同一个class文件中载入。但不幸的是JVM 却认为这个两个Class是不同的,即JVM认为不同的classloader载入的相同的名字的Class(即使是从同一个class文件中载入的)是不同的!这样做的原因我想大概也是主要出于安全性考虑,这样就保证所有的核心Java类都是system classloader载入的,我们无法用自己的classloader载入的相同名字的Class的实例来替换它们的实例。
DjO$f0BR e051Testing软件测试网 O7?\%R aw;G
看到这里,聪明的读者一定想到了该如何动态载入我们的Class,实例化,造型并调用了吧!
8J}j i$@w/mtE0
+_5H m-~ R&g0那就是利用面向对象的基本特性之一的多形性。我们把我们动态载入的Class的实例造型成它的一个system classloader所能识别的父类就行了!这是为什么呢?我们还是要再来分析一次。当我们用我们自己的classloader来动态载入这我们只要把这个Class的时候,发现它有一个父类Class,在载入它之前JVM先会载入这个父类Class,这个父类Class是system classloader所能识别的,根据委托机制,它将由system classloader载入,然后我们的classloader再载入这个Class,创建一个实例,造型为这个父类Class,注意了,造型成这个父类 Class的时候(也就是上溯)是面向对象的java语言所允许的并且JVM也支持的,JVM就使用system classloader再次载入这个父类Class,然后将此实例造型为这个父类Class。大家可以从这个过程发现这个父类Class都是由 system classloader载入的,也就是同一个class loader载入的同一个Class,所以造型的时候不会出现任何异常。而根据多形性,调用这个父类的方法时,真正执行的是这个Class(非父类 Class)的覆盖了父类方法的方法。这些方法中也可以引用system classloader不能识别的Class,因为根据全盘负责原则,只要载入这个Class的classloader即我们自己定义的 classloader能够定位和载入这些Class就行了。
)~ M7H4V&|D-f)U051Testing软件测试网T)Y*f'Av7lt#_
这样我们就可以事先定义好一组接口或者基类并放入CLASSPATH中,然后在执行的时候动态的载入实现或者继承了这些接口或基类的子类。还不明白吗?让我们来想一想Servlet吧,web application server能够载入任何继承了Servlet的Class并正确的执行它们,不管它实际的Class是什么,就是都把它们实例化成为一个Servlet Class,然后执行Servlet的init,doPost,doGet和destroy等方法的,而不管这个Servlet是从web- inf/lib和web-inf/classes下由system classloader的子classloader(即定制的classloader)动态载入。说了这么多希望大家都明白了。在applet,ejb等容器中,都是采用了这种机制.
} fW`b~0
j%Rhr V"a"h0对于以上各种情况,希望大家实际编写一些example来实验一下。
[@3Sup0
N2]u#G e"S+G*HNH M0最后我再说点别的, classloader虽然称为类加载器,但并不意味着只能用来加载Class,我们还可以利用它也获得图片,音频文件等资源的URL,当然,这些资源必须在CLASSPATH中的jar类库中或目录下。我们来看API的doc中关于ClassLoader的两个寻找资源和Class的方法描述吧:51Testing软件测试网R9rl H-{C wP
        public URL getResource(String name)51Testing软件测试网l*s j;l!z
        用指定的名字来查找资源,一个资源是一些能够被class代码访问的在某种程度上依赖于代码位置的数据(图片,音频,文本等等)。51Testing软件测试网b,ci,^(`9V}1~
               一个资源的名字是以'/'号分隔确定资源的路径名的。
$Sd2f2Ll/G1BX0               这个方法将先请求parent classloader搜索资源,如果没有parent,则会在内置在虚拟机中的classloader(即bootstrap classloader)的路径中搜索。如果失败,这个方法将调用findResource(String)来寻找资源。
+V w)M/n1ZF6b"^0        public static URL getSystemResource(String name)
"V YG)^E U?0               从用来载入类的搜索路径中查找一个指定名字的资源。这个方法使用system class loader来定位资源。即相当于ClassLoader.getSystemClassLoader().getResource(name)。
3? x-Fox1D#t0
U$U*H5Ri2lEj0例如:
m+a[%Jv J7W0   System.out.println(ClassLoader.getSystemResource("java/lang/String.class"));51Testing软件测试网2KT}F!c~-|
的结果为:51Testing软件测试网]"^7mE_D&fl
   jar:文件:/C:/j2sdk1.4.1_01/jre/lib/rt.jar!/java/lang/String.class51Testing软件测试网t|$u}Q Y&d
表明String.class文件在rt.jar的java/lang目录中。
*|T \n{Efa0t0因此我们可以将图片等资源随同Class一同打包到jar类库中(当然,也可单独打包这些资源)并添加它们到class loader的搜索路径中,我们就可以无需关心这些资源的具体位置,让class loader来帮我们寻找了!51Testing软件测试网P} e,SBD@yp


TAG: JAVA类

 

评分:0

我来说两句

Open Toolbar