前言
今天看Java代理的一些文章的时候,通过动态代理想到了反射的问题,然后就想到了以前面试的时候被问到的一个面试问题:
Class.forName与ClassLoader的区别?,自己当时虽然回答上来了,但是回答的并不具体,今天有空做个整理。
在Java中Class.forName()和ClassLoader都是对类进行加载,我们也知道在Class.forName中会加载静态代码块,但是ClassLoader并不会加载静态代码块。
从以上我们也可以推出来,其实ClassLoader是遵循了双亲委派模型,最终会调用类加载器来加载,它的功能是通过一个类的类名来获取该类的二进制字节流,然后将该字节流放入到JVM中。
我们可以查看Class.forName的源码:
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
在以上的源码中可以看到最终是调用forName0这个方法,这个方法中有四个参数:
- 第一个参数:类名
- 第二个参数:是否对类进行初始化,设置为true,则会执行类中的静态代码块
- 第三个参数:第三个参数是设定类加载器
因此我们可以使用Class.forName(String name, boolean initialize,ClassLoader loader),来自己设定是否进行初始化以及类加载器。
对于ClassLoader来说,Java中有三种ClassLoader,分别是:
BootstrapClassLoaderExtClassLoaderAppClassLoader
而在ClassLoader源码中,主要是这三种类加载器通过类的路径来加载该类生成二进制字节流放入JVM中。
/*
* The class loader used for loading installed extensions.
*/
static class ExtClassLoader extends URLClassLoader {
static {
ClassLoader.registerAsParallelCapable();
}
/**
* create an ExtClassLoader. The ExtClassLoader is created
* within a context that limits which files it can read
*/
public static ExtClassLoader getExtClassLoader() throws IOException
{
final File[] dirs = getExtDirs();
try {
// Prior implementations of this doPrivileged() block supplied
// aa synthesized ACC via a call to the private method
// ExtClassLoader.getContext().
return AccessController.doPrivileged(
new PrivilegedExceptionAction<ExtClassLoader>() {
public ExtClassLoader run() throws IOException {
int len = dirs.length;
for (int i = 0; i < len; i++) {
MetaIndex.registerDirectory(dirs[i]);
}
return new ExtClassLoader(dirs);
}
});
} catch (java.security.PrivilegedActionException e) {
throw (IOException) e.getException();
}
}
private static File[] getExtDirs() {
String s = System.getProperty("java.ext.dirs");
File[] dirs;
if (s != null) {
StringTokenizer st =
new StringTokenizer(s, File.pathSeparator);
int count = st.countTokens();
dirs = new File[count];
for (int i = 0; i < count; i++) {
dirs[i] = new File(st.nextToken());
}
} else {
dirs = new File[0];
}
return dirs;
}
......
}
那么哪些地方使用到了Class.forName或者ClassLoader呢?
- 在进行JDBC连接时,我们通常使用Class.forName去实现。
- 在Spring中的IOC使用ClassLoader。