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
两次加载使用的不是同一个类加载器,而是调用者的类加载器。








  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值