gpt4 book ai didi

java - 链式类加载器难题

转载 作者:太空宇宙 更新时间:2023-11-04 08:23:02 26 4
gpt4 key购买 nike

我在使用 Java 类加载器方面遇到了一些困难,也许有人可以解释一下这一点。我把问题的本质提炼如下:

共有三个类 - ClassLoaderTest , LoadedClassLoadedClassDep 。他们都走在不同的道路上。

ClassLoaderTest实例化一个新的 URLClassLoader -myClassLoader ,用剩余两个类的路径和它自己的类加载器(即应用程序类加载器)作为父类来启动它。然后它使用 Class.forName("com.example.LoadedClass", true, myClassLoader)加载LoadedClass通过反射(reflection)。 LoadedClass导入 LoadedClassDep 。如果我运行上面的代码,使用:

java -cp /path/to/the/ClassLoaderTest ClassLoaderTest "/path/to/LoadedClass" "/path/to/LoadedClassDep"

并使用命令行参数来启动 URLClassLoader一切正常。使用静态初始化程序,我确认这两个类已加载 URLClassLoader 的实例。 。但是,如果我这样做,这就是问题所在:

java -cp /path/to/the/ClassLoaderTest:/path/to/the/LoadedClass ClassLoaderTest "/path/to/LoadedClassDep"

无法加载 LoadedClassDep ( ClassNotFoundException )。 LoadedClass已正确加载,但带有 sun.misc.Launcher$AppClassLoader ,而不是 URLClassLoader !看起来,由于应用程序类加载器能够加载 LoadedClass它还尝试加载 LoadedClassDep ,忽略 URLClassLoader .

这是完整的源代码:

package example.bc;
public class ClassloaderTest {
public static void main(String[] args) {
new ClassloaderTest().run(args);
}

private void run(String[] args) {
URLClassLoader myClasLoader = initClassLoader(args);
try {
Class<?> cls = Class.forName("com.example.bc.LoadedClass", true, myClasLoader);
Object obj = cls.newInstance();
cls.getMethod("call").invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}

private URLClassLoader initClassLoader(String[] args) {
URL[] urls = new URL[args.length];

try {
for (int i = 0; i < args.length; i++) {
urls[i] = new File(args[i]).toURI().toURL();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return new URLClassLoader(urls, getClass().getClassLoader());
}
}

package com.example.bc;

import com.bc.LoadedClassDep;

public class LoadedClass {

static {
System.out.println("LoadedClass " + LoadedClass.class.getClassLoader().getClass());
}

public void call() {
new LoadedClassDep();
}
}

package com.bc;

public class LoadedClassDep {
static {
System.out.println("LoadedClassDep " + LoadedClassDep.class.getClassLoader().getClass());
}
}

我希望我已经说得足够清楚了。我的问题是,我只知道 ClassLoadeTest 的路径在编译时,我必须在运行时对其他路径使用字符串。那么,有什么想法可以让第二种情况发挥作用吗?

最佳答案

我希望应用程序类加载器在第二种情况下加载 LoadedClass,因为类加载器最初委托(delegate)给其父级 - 这是 standard behaviour 。在第二种情况下,LoadedClass 位于父级的类路径上,因此它会加载该类,而不是放弃并让 URLClassLoader 尝试。

然后,应用程序类加载器尝试加载 LoadedClassDep,因为它是在 LoadedClass 中直接导入和引用的:

public void call() {
new LoadedClassDep();
}

如果需要在运行时动态且独立地加载这些类,则不能通过这种方式在它们之间进行直接引用。

也可以更改尝试类加载器的顺序 - 请参阅 Java classloaders: why search the parent classloader first?对此进行一些讨论。

关于java - 链式类加载器难题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9161133/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com