如何在Java中更改默认类加载器?

假设我有三个类,example.ClassA,example.ClassB和example.ClassLoader。 ClassA打印出HelloWorld,ClassB导入example.ClassA并调用其main()方法。 如果我这样做:

java -cp Example.jar -Djava.system.class.loader = example.ClassLoader example.ClassA

它工作并使用我的类加载器。 但是,如果我这样做:

java -cp Example.jar -Djava.system.class.loader = example.ClassLoader example.ClassB

ClassB使用我的类加载器,但ClassA(由ClassB导入)使用默认的类加载器加载。

有没有办法强制Java总是使用我的类加载器(除非明确指定另一个类加载器)?

编辑:感谢下面的PaŭloEbermann的回答,我认为问题是我正在调用父类加载器(URLClassLoader)来加载我不需要触摸的类,并且那些加载的类设置为它的上下文类加载器,因此从它导入的类使用我的自定义加载器的父类加载器。 (令人困惑,抱歉)现在我可以通过手动读取每个类来使它工作,但是它似乎是多余的,因为我直接复制了URLClassLoader的代码。 有没有办法告诉父类加载器查找和定义类,但是将Class的上下文类加载器设置为自定义类?

如果你的类加载器是正确实现的,它将首先向其父类加载器询问应该加载的任何类。

加载器的父类加载器可能是通常的应用程序类加载器。 这意味着您的类加载器加载的每个类将首先在应用程序类加载器上进行搜索,并且只有在未找到时才会在您的类加载器上进行搜

由类加载器定义的所有类也将在类加载器上搜索所需的类。 如果他们不这样做,你的ClassA并没有真正装载你的装载机。

如果这没有帮助,您需要显示一些关于如何获得结果的代码。


关于该做什么的想法:

class ModifyingClassLoader extends URLClassLoader { // TODO: add constructors private boolean needsModifying(String name) { // TODO } private byte[] modifyClass(InputStream original) throws IOException { // TODO } public Class findClass(String name) throws { if(needsModifying(name)) { try { InputStream classData = getResourceAsStream(name.replace('.', '/') + ".class"); if(classData == null) { throw new ClassNotFoundException("class " + name + " is not findable"); } byte[] array = modifyClass(classData); return defineClass(name, array, 0, array.length); } catch(IOException io) { throw new ClassNotFoundException(io); } } else { return super.findClass(name); } } } 

对你的问题:

有没有办法告诉父类加载器查找和定义类,但是将Class的上下文类加载器设置为自定义类?

defineClass类的ClassLoader始终是调用defineClass方法来创建类的类。 ( 上下文类加载器是另一回事 – 它是特定于线程的,并且仅由明确想要使用它的类使用,而不是由解析它们自己的直接依赖项的类使用。)