庖丁解牛--Java的类加载机制
Java的类加载机制是最容易被忽略的知识,不管是基础,还是往高级开发进阶,都需要了解类的加载机制。
今天从Java中常见的异常 ClassNotFoundException说起,来说说"双亲委托"
ClassNotFoundException
我们知道发生这个异常的原因是找不到某个类,但具体是为什么找不到这个类呢?当然最简单的就是当前项目路径下没有这个类。
那么Java是怎么查找项目路径下的类的呢,看看下面这段代码
Alt text
public class Ming { public static void main(String[] args) { System.out.println("Ming looking for socker"); Socker socker = new Socker(); }}
编译运行
$ javac Ming.java
Ming.java:7: 错误: 找不到符号
Socker socker = new Socker();
^
符号: 类 Socker
位置: 类 Ming
Ming.java:7: 错误: 找不到符号
Socker socker = new Socker();
^
符号: 类 Socker
位置: 类 Ming
2 个错误
错误很明显,Java在MingHouse下面找不到Socker类,因为Scoker在另一个路径WangHouse下面。眼尖的同学应该会留意到System.out这句日志方法没有报错,说明Java找到了这个类。可是我们没有import,也没有在目录下有这个类,它是系统类,不过Java是怎么找到它的还是得说明一下。
双亲委托
Java类的加载是由几个ClassLoader进行的,他们分别是
· BootStrapClassLoader
· ExtensionClassLoader
· AppClassLoader
他们之间的区别呢,可以简单理解为加载路径的不同。BootStrap负责加载系统核心类,Extension负责加载扩展类,而AppClassLoader负责加载当前app下面的所有jar和class文件。
还记得JAVA_HOME这个常量吗?通常配置Java环境第一件事就是设置这个常量,因为这样ExtensionClassLoader才能去找到 jre/lib/ext/ 下的jar和class。他们的加载顺序是怎样的呢?就上面代码的例子来说
小明:爸!我找不到袜子!
小明爸爸:找你妈去。
小明:妈!我找不到袜子!
小明妈妈:我也找不到!
在这个例子里,
· 小明->AppClassLoader
· 小明爸爸->ExtensionClassLoader
· 小明妈妈->BootStrapClassLoader
这就是双亲委托
了。
我们可以用这个代码看看当前类是哪个ClassLoader加载的
public class Ming { public static void main(String[] args) { System.out.println("class loader : " + Ming.class.getClassLoader()); Socker socker = new Socker(); }}
输出说明,Ming这个类是由AppClassLoader加载的
class loader : AppClassLoader
总的说,AppClassLoader会现在当前的classpath下找,找不到就问父级ExtensionClassLoader要,再找不到,ExtensionClassLoader就会管BootStrapClassLoader要。实在找不到就会ClassNotFound了.
到这里应该就明白,System类是由ExtensionClassLoader去查找加载,因为已经在JAVA_HOME里有,所以加载的到,而Socker不在ClassLoader的class path中,所以加载不到。
举一反三
按照双亲委托的机制,我们是没法找到在WangHouse里的Socker的。因为WangHouse的路径并不在我们ClassLoader里。
但是!
我们还是有办法在不import的情况下,通过自定义ClassLoader的方式,来找到WangHouse里的Socker。具体怎么实现呢?
明天我们会接着讲。
本文暂时没有评论,来添加一个吧(●'◡'●)