JVM成神之路-类加载机制-双亲委派,破坏双亲委派( 五 )

loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}
再看看( name,)函数:
protected Class loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// 1、检查请求的类是否已经被加载过了Class c = findLoadedClass(name);if (c == null) {try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// 如果父类加载器抛出ClassNotFoundException,说明父类加载器无法完成加载请求}if (c == null) {// 在父类加载器无法加载的时候,再调用本身的findClass方法来进行类加载c = findClass(name);}}if (resolve) {resolveClass(c);}return c;}}
检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回 。如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用.(name, false);).或者是调用类加载器来加载 。如果父加载器及类加载器都没有找到指定的类,那么调用当前类加载器的方法来完成类加载 。
换句话说,如果自定义类加载器,就必须重写方法!
的默认实现如下:
protected Class findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);}
可以看出,抽象类的函数默认是抛出异常的 。而前面我们知道,在父加载器无法加载类的时候,就会调用我们自定义的类加载器中的函数,因此我们必须要在这个函数里面实现将一个指定类名称转换为Class对象.
如果是读取一个指定的名称的类为字节数组的话,这很好办 。但是如何将字节数组转为Class对象呢?很简单,Java提供了方法,通过这个方法,就可以把一个字节数组转为Class对象啦~
主要的功能是:
将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组 。如,假设class文件是加密过的,则需要解密后作为形参传入函数 。
默认实现如下:
protected final Class defineClass(String name, byte[] b, int off, int len)throws ClassFormatError{return defineClass(name, b, off, len, null);}
函数调用过程:
示例
首先,我们定义一个待加载的普通Java类:Test.java 。放在com..demo包下:
package com.xdwang.demo;public class Test {public void hello() {System.out.println("恩,是的,我是由 " + getClass().getClassLoader().getClass() + " 加载进来的");}}
如果你是直接在当前项目里面创建,待Test.java编译后,请把Test.class文件拷贝走,再将Test.java删除 。因为如果Test.class存放在当前项目中,根据双亲委派模型可知,会通过sun.misc.$ 类加载器加载 。为了让我们自定义的类加载器加载,我们把Test.class文件放入到其他目录 。
接下来就是自定义我们的类加载器:
import java.io.FileInputStream;import java.lang.reflect.Method;public class Main {static class MyClassLoader extends ClassLoader {private String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}private byte[] loadByte(String name) throws Exception {name = name.replaceAll("\\.", "/");FileInputStream fis = new FileInputStream(classPath + "/" + name+ ".class");int len = fis.available();byte[] data = http://www.kingceram.com/post/new byte[len];fis.read(data);fis.close();return data;}protected Class findClass(String name) throws ClassNotFoundException {try {byte[] data = http://www.kingceram.com/post/loadByte(name);return defineClass(name, data, 0, data.length);} catch (Exception e) {e.printStackTrace();throw new ClassNotFoundException();}}};public static void main(String args[]) throws Exception {MyClassLoader classLoader = new MyClassLoader("D:/test");//Test.class目录在D:/test/com/xdwang/demo下Class clazz = classLoader.loadClass("com.xdwang.demo.Test");Object obj = clazz.newInstance();Method helloMethod = clazz.getDeclaredMethod("hello", null);helloMethod.invoke(obj, null);}}