(部分内容系转载 )
Java中一共有四个类加载器,之所以叫类加载器,是程序要用到某个类的时候,要用类加载器载入内存。
这四个类加载器分别为:Bootstrap ClassLoader、Extension ClassLoader、AppClassLoader
和URLClassLoader,他们的作用其实从名字就可以大概推测出来了。其中AppClassLoader在很多地方被叫做System ClassLoader
Bootstrap ClassLoader是在JVM开始运行的时候加载java的核心类,是用C++编写的,它用来加载核心类库,在JVM源代码中这样写道:
static const char classpathFormat[] =
"%/lib/rt.jar:"
"%/lib/i18n.jar:"
"%/lib/sunrsasign.jar:"
"%/lib/jsse.jar:"
"%/lib/jce.jar:"
"%/lib/charsets.jar:"
"%/classes";
Extension ClassLoader是用来加载扩展类,即/lib/ext中的类。
AppClassLoader用来加载Classpath的类,是和我们关系最密切的类。
URLClassLoader:在javaweb项目中经常用到通过xml来配置使用的类,如tomcat体系中就需要根据xml加载指定servlet类。此时就要使用到URLClassLoader,这个类是如何工作的?
测试代码使用了一个inter接口,在项目工程的路径中没有提供实现类,而自定义了一个实现类并打包在ForLoad.jar文件中:
1 public class Test { 2 3 public static void main(String[] args) throws IOException { 4 URL[] urls = new URL[1]; 5 File file = new File("D:\\ForLoad.jar"); 6 System.out.println(file.exists()); 7 URLClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()}); 8 try { 9 Class<inter> forLoadClazz = (Class<inter>) loader.loadClass("classload.Forload"); 10 inter inter = (inter) forLoadClazz.newInstance(); 11 inter.invoke(); 12 } catch (ClassNotFoundException e) { 13 e.printStackTrace(); 14 } catch (InstantiationException e) { 15 e.printStackTrace(); 16 } catch (IllegalAccessException e) { 17 e.printStackTrace(); 18 } 19 } 20 }
代码非常简单,可以看到第11行顺利执行了,说明实现类被顺利加载到。
这里有两个细节要注意:
1.ForLoad.jar必须正确打包,目录结构要按照类的路径来设置,否则抛出ClassNotFoundException,
2.loadClass这里要写全限定名
类加载的双亲委派模型
当前classpath下如果有classload.Forload 的话,会去加载这个类,而不是url指定位置的那个类
为什么呢?以下是ClassLoader的 loadClass实现:
发现首先去要求父加载器去加载类,只有当父亲加载不到的时候,才去调用自己的findClass方法。这样就可以解释了,因为夫加载器顺利加载到了类路径下的那个类,就屏蔽了URLClassLoader的作用。
这么做是为什么呢?百度了一下发现,主要是java类加载为了安全考虑,防止重要类被hack:如Object,String这些类如果有被替换实现的话,会导致不可预计的结果。熟悉攻击的就知道,unix环境下黑客重要的一招就是通过获取到root之后替换某些命令的含义。