一:类装载器ClassLoader
1.Bootstrap:根类加载器。他用来加载java的核心类,并不继承自java.lang.ClassLoader。他负责加载jre/lib/rt.jar里的所有class,由c++语言实现。开发者无法直接通过引用进行获取。
java虚拟机入口源码:sun.misc.Launcher
public Launcher() {
Launcher.ExtClassLoader var1;
try {
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
Thread.currentThread().setContextClassLoader(this.loader);
String var2 = System.getProperty("java.security.manager");
public ClassLoader getClassLoader() {
return this.loader;
}
public static URLClassPath getBootstrapClassPath() {
return Launcher.BootClassPathHolder.bcp;
}
private static URL[] pathToURLs(File[] var0) {
URL[] var1 = new URL[var0.length];
for(int var2 = 0; var2 < var0.length; ++var2) {
var1[var2] = getFileURL(var0[var2]);
}
return var1;
}
static URL getFileURL(File var0) {
try {
var0 = var0.getCanonicalFile();
} catch (IOException var3) {
;
}
try {
return ParseUtil.fileToEncodedURL(var0);
} catch (MalformedURLException var2) {
throw new InternalError(var2);
}
}
}
2.Extension:扩展类加载器,加载扩展目录,lib/ext或java.ext.dirs系统属性指定的目录中的jar包的类。java语言实现,父类加载器:null。
3:System:系统类加载器/应用类加载器。可通过ClassLoader.getSystemClassLoader()来获取系统类加载器。自定义的类加载器以此加载器作为父加载器。父类加载器为扩展类加载器。
static class AppClassLoader extends URLClassLoader {
public static ClassLoader getAppClassLoader(final ClassLoader extcl)
throws IOException
{
final String s = System.getProperty("java.class.path");
final File[] path = (s == null) ? new File[0] : getClassPath(s);
return AccessController.doPrivileged(
new PrivilegedAction<AppClassLoader>() {
public AppClassLoader run() {
URL[] urls =
(s == null) ? new URL[0] : pathToURLs(path);
return new AppClassLoader(urls, extcl);
}
});
}
}
可以尝试一下:
System.out.println(System.getProperty("java.class.path"));
打印的结果除了父类加载器加载的jar和class外,还有当前项目引入的jar和java文件编译生成的class文件。
好了 既然知道了3个类加载器。接下来就要知道他们的关系:
1.执行顺序Bootstrap->Extension->System
2.System的父类加载器是Extension,Extension的父类加载器是Bootstrap。也许有看源码的同学发现,AppClassLoader和ExtClassLoader的父类不是URLClassLoader嘛,不好意思,老弟也没看懂这部分源码,暂时记住就得了,能力强了再研究...(来自一个小萌新的哭泣QAQ)。
下面我们理解一下类加载器的加载顺序:双亲委托
一个类在查找class和resource时,如果缓存中已经加载过,直接拿来用。如果没有,会交给父类加载器,重复之前的操作,这样递归下去直到走到Bootstrap。如果Bootstrap找到,返回,如果没有,一层一层返回找,最后回到本身。
自定义ClassLoader:
执行的class文件:
public class WuMai extends ClassLoader {
public WuMai() {
}
public void aaa() {
System.out.println("啊啊啊啊啊,给我个对象吧!!!");
}
}
自定义类加载器:
public class MyClassLoader extends ClassLoader{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] result = getMyClass(name);
if (result == null) {
throw new FileNotFoundException(name);
} else {
return defineClass(name, result, 0, result.length);
}
} catch (Exception e) {
e.printStackTrace();
}
throw new ClassNotFoundException(name);
}
private byte[] getMyClass(String name){
InputStream in = null;
ByteArrayOutputStream out = null;
String path = "D:/HelloWorld/"+name+".class";
try {
in = new FileInputStream(path);
out = new ByteArrayOutputStream();
byte[] buff = new byte[2048];
int len = 0;
while ((len = in.read(buff))!=-1){
out.write(buff,0,len);
}
return out.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
测试方法
public class Test {
public static void main(String[] args) {
MyClassLoader myClassLoader = new MyClassLoader();
try {
Class clazz = myClassLoader.loadClass("WuMai");
if (clazz!=null){
Object obj = clazz.newInstance();
Method method = clazz.getMethod("aaa",null);
method.invoke(obj,null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
嘻嘻,就这些,我把我会的都告诉你了,奖励个赞吧!