Java ClassLoader更改

我有一些A类:

 public class A { public A(String str) { System.out.println("Create A instance: " + str); } public void methodA() { System.out.println("#methodA1()"); } } 

我的类加载器实现:

 public class MyClassLoader extends ClassLoader { public MyClassLoader() { super(); } @Override public synchronized Class loadClass(String name) throws ClassNotFoundException { System.out.println("Load: " + name); return super.loadClass(name); } } 

现在我尝试更改当前线程中的默认类加载器:

 import java.util.ArrayList; import java.util.List; public class ChangeLoaderTest { public static void main(String[] args) { // Save class loader so that we can restore later. ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); MyClassLoader newLoader = new MyClassLoader(); try { // Set new classloader. Thread.currentThread().setContextClassLoader(newLoader); // My class. A a = new A("1"); a.methodA(); // Standard Java class. List list = new ArrayList(); list.add(2); list.add(3); } finally { // Restore. Thread.currentThread().setContextClassLoader(oldLoader); } } } 

ChangeLoaderTest输出:

 Create A instance: 1 #methodA1() 

没有人

 Load: ... 

为什么? 如何将ClassLoader更改为某个线程?

正如Marko Topolnik所指出的, 上下文类加载器是供框架使用的 。 要自己使用类加载器,必须调用loadClass("somepackage.A") ,然后使用reflectionAPI创建A的新实例( Class.newInstance() )。

由于调用代码不知道A – 它使用不同的类加载器,因此您无法直接在源代码中使用A或其方法。 可以由普通类加载器加载的A的接口或基类可用于避免reflection。

 interface AIF{ void someMethod(); } class A implements AIF{ public void someMethod(){} } public void test(){ MyLoader loader = new MyLoader(); Class cla = loader.loadClass("A"); AIF a = (AIF) cla.newInstance(); a.someMethod(); } 

contextClassLoader机制被像new这样的基本Java操作使用。 只有这样,各种框架才能访问负责的上下文类加载器并加载资源,类等.Java将始终使用加载正在执行的代码的类加载器。 这是您通过ChangeLoaderTest.class.getClassLoader()访问的那个 – 而且您无法对此进行任何操作。

我认为发生的事情是你的应用程序的类加载器也是你的类加载器的“父”可以找到A并加载它。 因此,您的类加载器将不会被搜索或用于加载A

说实话,我对类加载器没有多少经验,但是如果你inheritance了一个使用URL作为类路径的子类(这样它可以找到类文件)并且父类加载器无法加载它(不是类路径的一部分) ),将使用您的自定义。