![89c0efcb0610442a972ff575307f21af.png](https://i-blog.csdnimg.cn/blog_migrate/82657f50e094bb86c3b32b6edbb1d15d.jpeg)
类加载器是做什么的,类需要加载到虚拟机中,类加载器负责将Java类加载到内存中,并生成Class类的实例对象。
一、简单使用类加载器
首先让我们一起通过一个例子来简单的使用类加载器加载class文件,并获取class对象
首先创建一个对象类
public class DemoItem {
public void demo()
{
System.out.println("demo!!");
}
}
将编译生成的class复制到E:/cltmp/路径下,并删除DemoItem这个类,防止会被默认加载,然后创建类加载器,并获取class文件加载类。
URL url = new URL("file:/E:/cltmp/");
URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
Class cl = classLoader.loadClass("DemoItem");
System.out.println(cl.equals(cl));
二、类加载器常用函数解析
现在已经使用类加载器获取到了DemoItem的class对象了。让我们一起看下类加载器中一个核心的函数loadClass(String name),这个函数负责获取全名为name的类,返回对象为Class实例,代码如下
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
loadClass中首先调用findLoadedClass查询类是否被当前类加载器加载,如果没有找到,则去父级类加载器,即扩展类加载器中parent.loadClass(name, false)查询是否已经加载,如果还是没有就到BootstrapClassLoader中查询是否加载,如果还是找不到,则类还没有加载,调用findClass()函数,查找加载路径下的class文件,如果还是找不到在findClass()函数中抛出ClassNotFoundException异常。
findClass这个函数负责将制定加载路径的class文件加载进虚拟机中,URLClassLoader中findClass函数代码如下
protected Class<?> findClass(final String name) throws ClassNotFoundException
{
final Class<?> result;
try {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
String path = name.replace('.', '/').concat(".class");
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
return defineClass(name, res);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
} else {
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
已经基本搞清楚类加载器怎么工作的了,下一篇我们一起研究下类加载器的分类和加载器的双亲委派模式。