JAVA类加载
类加载器
java中有三种类加载器
-Bootstrap ClassLoader (引导类加载器) 该类加载器实现于JVM层,采用C++编写
- Extension ClassLoader (扩展类加载器)
- App ClassLoader (系统类加载器) 默认的类加载器
BootstrapClassLoader只加载包名为java、javax、sun等开头的类)。
扩展类加载器(ExtensionsClassLoader),由sun.misc.Launcher$ExtClassLoader类实现,用来在/jre/lib/ext或者java.ext.dirs中指明的目录加载java的扩展库.
App类加载器/系统类加载器(AppClassLoader),由sun.misc.Launcher$AppClassLoader实现,一般通过通过(java.class.path或者Classpath环境变量)来加载Java类,也就是我们常说的classpath路径。
自定义类加载器
除开上文提到的三种加载器,我们还可以自定义加载器.
本地类加载
public class ClassLoaderStudy extends ClassLoader {
private static final String testClassName = "top.longlone.Hello";
private static final byte[] testClassBytes = Base64.getDecoder().decode("yv66vgAAADQAHAoACAARBwASCgACABEIABMKAAIAFAoAAgAVBwAWBwAXAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABWhlbGxvAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAKSGVsbG8uamF2YQwACQAKAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAZIZWxsbyAMABgAGQwAGgAbAQASdG9wL2xvbmdsb25lL0hlbGxvAQAQamF2YS9sYW5nL09iamVjdAEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsAIQAHAAgAAAAAAAIAAQAJAAoAAQALAAAAHQABAAEAAAAFKrcAAbEAAAABAAwAAAAGAAEAAAADAAEADQAOAAEACwAAACwAAgACAAAAFLsAAlm3AAMSBLYABSu2AAW2AAawAAAAAQAMAAAABgABAAAABQABAA8AAAACABA=");
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (name.equals(testClassName)) {
return defineClass(testClassName, testClassBytes, 0, testClassBytes.length);
}
return super.findClass(name);
}
public static void main(String[] args) throws Exception {
ClassLoaderStudy loader = new ClassLoaderStudy();
Class testClass = loader.loadClass(testClassName);
Object o = testClass.newInstance();
Method sayHello = o.getClass().getMethod("hello", String.class);
String longlone = (String) sayHello.invoke(o, "Longlone");
System.out.println(longlone);
}
}
我们要继承ClassLoader类和覆盖findClass()方法.其中最核心的逻辑是defineClass方法
protected final Class<?> defineClass(byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(null, b, off, len, null);
}
String name: 这是类的全限定名。在类加载器的作用下,该类将会被加载到Java虚拟机中。byte[] b: 这是一个字节数组,包含了一个类的字节码。这个字节数组通常是通过读取一个类文件(以 .class 结尾的文件)获得的。字节码数组应该包含有效的Java类文件的内容。int off: 这是字节数组b中的起始偏移量,表示开始转换的位置。int len: 这是要转换的字节数,表示从偏移量off处开始的连续字节的长度。
远程类加载
import java.net.URL;
import java.net.URLClassLoader;
public class ClassLoaderDemo {
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:8080/examples/");
URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
Class clazz = classLoader.loadClass("com.test.Test");
clazz.newInstance();
}
}
双亲委派机制
简单来说就是类加载器接到加载类的请求时,首先会先将任务委托给父类加载器,接着请求父类加载这个类,当父类加载器无法加载时(其目录搜素范围没有找到所需要的类时),子类加载器才会进行加载使用。这样可以避免有些类被重复加载。

我们可以看到我们自定义的类是在最下面的,所以我们是无法更改java内部的三个加载器所负责的类.