//查看被加载的TestBean类型是被那个类加载器加载的
System.out.println(typeLoaded.getClassLoader());
} catch (Exception e) {
e.printStackTrace();
}
}
}
对应的输出如下:
D:"DEMO"dev"Study"ClassLoaderTest"bin
sun.misc.Launcher$AppClassLoader@197d257
(说明:当前类路径默认的含有的一个条目就是工程的输出目录)
测试二:
将当前工程输出目录下的…/classloader/test/bean/TestBean.class打包进test.jar剪贴到< Java_Runtime_Home >/lib/ext目录下(现在工程输出目录下和JRE扩展目录下都有待加载类型的class文件)。再运行测试一测试代码,结果如下:
D:"DEMO"dev"Study"ClassLoaderTest"bin
sun.misc.Launcher$ExtClassLoader@7259da
对比测试一和测试二,我们明显可以验证前面说的双亲委派机制,系统类加载器在接到加载classloader.test.bean.TestBean类型的请求时,首先将请求委派给父类加载器(标准扩展类加载器),标准扩展类加载器抢先完成了加载请求。
测试三:
将test.jar拷贝一份到< Java_Runtime_Home >/lib下,运行测试代码,输出如下:
D:"DEMO"dev"Study"ClassLoaderTest"bin
sun.misc.Launcher$ExtClassLoader@7259da
测试三和测试二输出结果一致。那就是说,放置到< Java_Runtime_Home >/lib目录下的TestBean对应的class字节码并没有被加载,这其实和前面讲的双亲委派机制并不矛盾。虚拟机出于安全等因素考虑,不会加载< Java_Runtime_Home >/lib存在的陌生类,开发者通过将要加载的非JDK自身的类放置到此目录下期待启动类加载器加载是不可能的。做个进一步验证,删除< Java_Runtime_Home >/lib/ext目录下和工程输出目录下的TestBean对应的class文件,然后再运行测试代码,则将会有 ClassNotFoundException异常抛出。有关这个问题,大家可以在java.lang.ClassLoader中的 loadClass(String name, boolean resolve)方法中设置相应断点运行测试三进行调试,会发现findBootstrapClass0()会抛出异常,然后在下面的findClass 方法中被加载,当前运行的类加载器正是扩展类加载器(sun.misc.Launcher$ExtClassLoader),这一点可以通过JDT中变量视图查看验证。
(5)被不同的ClassLoader加载的两个类之间有什么限制和不同?
现在我们来看一下一个现象:
在eclipse里面我是这样做的:
OneCls.java
package org.corey.one;
import org.corey.two.TwoCls;
public class OneCls {
public OneCls() {
System.out.println();
TwoCls two = new TwoCls();
two.say();
}
}
TwoCls.java
package org.corey.two;
public class TwoCls {
public void say() {
System.out.println("i am two");
}
}
Demo.java:
package org.corey.Demo;
import org.corey.one.OneCls;
public class Demo {
/**
* @param args
*/
public static void main(String[] args) {
OneCls one=new OneCls();
}
}
在这里,我们来仔细看下,one引用了two,demo引用了one,这是三个类都是由AppClassLoader加载的;运行正常;
把OneCls打成jar包,放在lib/ext路径下面,然后在工程里面引入这个jar包;运行:异常,这是因为:
Demo是由AppClassLoader载入,委托给双亲加载失败后,由AppClassLoader加载,而加载OneCls的时候,委托给双亲,被ExtClassLoader加载成功,但是在载入OneCls的时候,同时引用了TwoCls,但是ExtClassLoader引用 TwoCls失败,但是他只会委托给双亲,而不会委托给AppClassLoader这个儿子,所以会出现异常;
责任编辑:小草