Class.forName(String className)使用哪个类加载器?

来源:互联网 发布:算法概念和特征 编辑:程序博客网 时间:2024/05/21 11:30

不看源码,以为Class.forName(String className)使用的是系统类加载器,看了源码才知道不是这么回事。

 public static Class<?> forName(String className)                 throws ClassNotFoundException {        return forName0(className, true, ClassLoader.getCallerClassLoader());    }
通过 ClassLoader.getCallerClassLoader()获取类加载器:
 // Returns the invoker's class loader, or null if none.    // NOTE: This must always be invoked when there is exactly one intervening    // frame from the core libraries on the stack between this method's    // invocation and the desired invoker.    static ClassLoader getCallerClassLoader() {        // NOTE use of more generic Reflection.getCallerClass()        Class caller = Reflection.getCallerClass(3);        // This can be null if the VM is requesting it        if (caller == null) {            return null;        }        // Circumvent security check since this is package-private        return caller.getClassLoader0();    }
看第一行注释,返回的是调用者的类加载器。显然,调用者的类加载器不一定是系统类加载器,比如我们使用了自定义类加载器。看下面的例子:

User.java

package org.zzj;public class User {}
UserService.java
package org.zzj;public class UserService {public void add() {try {System.out.println(Class.forName("org.zzj.User").getClassLoader());} catch (ClassNotFoundException e) {e.printStackTrace();}}}
ClassForNameTest.java
package org.zzj;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Method;public class ClassForNameTest {public static void main(String[] args) throws Exception {System.out.println(Class.forName("org.zzj.User").getClassLoader());MyClassLoader classLoader = new MyClassLoader();Class<?> clazz = classLoader.loadClass("org.zzj.UserService");Method method = clazz.getMethod("add");method.invoke(clazz.newInstance());}}class MyClassLoader extends ClassLoader {@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";InputStream in = getClass().getResourceAsStream(fileName);if (in == null) {return super.loadClass(name);}byte[] b = null;try {b = new byte[in.available()];in.read(b);in.close();} catch (IOException e) {e.printStackTrace();}return defineClass(name, b, 0, b.length);}}
输出:
sun.misc.Launcher$AppClassLoader@19821forg.zzj.MyClassLoader@14318bb
两次加载使用的不是同一个类加载器,而是调用者的类加载器。








0 0
原创粉丝点击