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

不看源码,以为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 {
	@Override
	public 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@19821f
org.zzj.MyClassLoader@14318bb
两次加载使用的不是同一个类加载器,而是调用者的类加载器。








你可能感兴趣的:(Java虚拟机)