③. 扩展类加载器 Extension
①. Java语言编写,由sum.music.Launcher$ExtClassLoader实现
②. 派生于ClassLoader类,父类加载器为启动类加载器
③. 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载
④. 应用程序(系统)类加载器 AppClassLoader
①. java语言编写,由sum.misc.Launcher$AppClassLoader实现
②. 派生于ClassLoader类,父类加载器为扩展类加载器
③. 它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库
④. 该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载
⑤. 通过ClassLoader的getSystemClassLoader()方法可以获取到该类加载器
⑤. 用户自定义类加载器
①. 在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们换可以自定义类加载器,来定制类的加载方式(自定义类加载器通常需要继承于 ClassLoader)
②. 体现Java语言强大生命力和巨大魅力的关键因素之一便是,Java 开发者可以自定义类加载器来实现类库的动态加载,加载源可以是本地的JAR包,也可以是网络上的远程资源
③. 自定义 ClassLoader 的子类时候,我们常见的会有两种做法:
重写loadClass()方法(不推荐,这个方法会保证类的双亲委派机制)
重写findClass()方法 -->推荐
这两种方法本质上差不多,毕竟loadClass()也会调用findClass(),但是从逻辑上讲我们最好不要直接修改loadClass()的内部逻辑。建议的做法是只在findClass()里重写自定义类的加载方法,根据参数指定类的名字,返回对应的Class对象的引用。
④. 如何手写一个简单的自定义加载器
public class UserClassLoader extends ClassLoader { private String rootDir; public UserClassLoader(String rootDir) { this.rootDir = rootDir; } /** * 编写findClass方法的逻辑 */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 获取类的class文件字节数组 byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { //直接生成class对象 return defineClass(name, classData, 0, classData.length); } } /** * 编写获取class文件并转换为字节码流的逻辑 * @param className * @return */ private byte[] getClassData(String className) { // 读取类文件的字节 String path = classNameToPath(className); try { InputStream ins = new FileInputStream(path); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; // 读取类文件的字节码 while ((len = ins.read(buffer)) != -1) { baos.write(buffer, 0, len); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 类文件的完全路径 */ private String classNameToPath(String className) { return rootDir + "\\" + className.replace('.', '\\') + ".class"; } public static void main(String[] args) { String rootDir = "D:\\code\\workspace_teach\\JVMdachang210416\\chapter02_classload\\src\\"; try { //创建自定义的类的加载器1 UserClassLoader loader1 = new UserClassLoader(rootDir); Class clazz1 = loader1.findClass("com.xiaozhi.java3.User"); //创建自定义的类的加载器2 UserClassLoader loader2 = new UserClassLoader(rootDir); Class clazz2 = loader2.findClass("com.xiaozhi.java3.User"); //clazz1与clazz2对应了不同的类模板结构 System.out.println(clazz1 == clazz2); System.out.println(clazz1.getClassLoader()); System.out.println(clazz2.getClassLoader()); Class clazz3 = ClassLoader.getSystemClassLoader().loadClass("com.xiaozhi.java3.User"); System.out.println(clazz3.getClassLoader()); System.out.println(clazz1.getClassLoader().getParent()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }