1 ClassLoader只是一个普通抽象类,它的工作是从类名得到Class。ClassLoader与其他类的唯一不同之处是它是为JVM服务的,属于“公务员”,例如Thread就带有getContextClassLoader()和setContextClassLoader()方法;
2 ClassLoader的实现类URLClassLoader完成工作的方法是根据传入的class目录或jar文件的URL读取二进制文件,并转化为Class;
3 ClassLoader有个成员变量parent,使用ClassLoader获取Class时,默认会先用它的parent尝试获取该Class,没有的话自己再尝试。当然,你可以自己实现ClassLoader来改变这一行为。例如:
import java.net.URL; import java.net.URLClassLoader; /** * 先自己尝试获取Class,不行再找parent */ public class OverridingClassLoader extends URLClassLoader { private final ClassLoader parent; public OverridingClassLoader(URL[] urls, ClassLoader parent) { super(urls, null); this.parent = parent; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { try { return super.loadClass(name); } catch (Exception e) { return parent.loadClass(name); } } }
4 JVM不会关心进程里有多少个ClassLoader实例,也不关心它们从各种途径读出来多少个Class,所以类名相同的Class可以同时存在多个。这会造成一些混乱,比如,假设两个类Person和Student有继承关系,并被一个ClassLoader读进了JVM,然后某个ClassLoader从另一个jar文件又读进来一个Person,这时第一个Student和第二个Person将没有任何关系,instanceof或isAssignableFrom均会返回false;
5 第三方库或框架比如Spring、Hadoop往往会尝试调用Thread.currentThread().getContextClassLoader()来获取ClassLoader为己用,所以你若是想要它们使用你的自定义ClassLoader,记得提前调用Thread.currentThread().setContextClassLoader()把你的ClassLoader设进去。Tomcat就是这么做的,每个webapp的Thread.currentThread().getContextClassLoader()都会返回与该webapp绑定的一个WebappClassLoader实例,所以使用不同jar包的webapp们不会互相影响。