URLClassLoader使用以及特性详解
类加载器类型
Java中有4种类加载器:
-
BootstrapClassLoader 最顶层的加载类,主要加载核心类库(c++实现) ExtentionClassLoader 扩展的类加载器 AppClassLoader也称为SystemAppClass 加载当前应用的classpath的所有类。 自定义类加载器。
注意:classpath即为java编译的源文件以及一些第三方库所在的文件夹或jar包。详细了解见
加载顺序
双亲(parent)委托机制
遇到加载请求,先把这个请求交给父加载器加载。只有父类加载器找不到class文件,子类才可以加载。所以加载顺序一般是 BootstrapClassLoader -> ExtentionClassLoader -> AppClassLoader -> 自定义类加载器(默认)
父加载器不是父类
加载器类中有一个变量指向父加载器,更继承没啥关系。一般在加载器的构造函数中可以指定父加载器,没指定则默认为AppClassLoader ,指定为null父加载器则为BootstrapClassLoader。
URLClassLoader
可以指定一串路径,然后再些路径下面寻找将要加载的类。这个类加载器如果没有指定的话父类加载器也是AppClassLoader
举个例子。 我们有一个Hello.class文件,位于d:/目录下
public class Hello { public Hello() { System.out.println("hello!!!!!!!!!"); } }
通过URLClassLoader加载这个类
public class ClassLoaderTest { @Test public void urlClassLoaderTest() throws Exception { File file = new File("d:/"); URL url = file.toURI().toURL(); ClassLoader loader=new URLClassLoader(new URL[]{ url}); Class<?> clazz = loader.loadClass("Hello"); System.out.println("当前类加载器"+clazz.getClassLoader()); System.out.println("父类加载器"+clazz.getClassLoader().getParent()); clazz.newInstance(); } }
输出:
如果在当前的classpath也放置一个Hello.class文件,那么就会被APPClassLoader加载,而且加载不到d盘的那个文件。
public class Hello { public Hello() { System.out.println("this is another hello class"); } }
输出: 但是若把URLClassLoader的父类设置为启动类加载器,这样就避免了委派给AppClassLoader时加载了classpath下的同名类文件。
@Test public void urlClassLoaderTest() throws Exception { File file = new File("d:/"); URL url = file.toURI().toURL(); ClassLoader loader=new URLClassLoader(new URL[]{ url},null);//设为null表示由根加载器加载 Class<?> clazz = loader.loadClass("Hello"); System.out.println("当前类加载器"+clazz.getClassLoader()); System.out.println("父类加载器"+clazz.getClassLoader().getParent()); clazz.newInstance(); }
输出:
与反射创建类的区别
反射创建常用Class.forName,通过类的全限定类名创建,但是只能创建classpath内的类,如果一个类不在classpath中。就只能使用类加载器来创建了。 参考:
上一篇:
IDEA上Java项目控制台中文乱码