真的可以替换Java System类Loader吗?
Java具有可以替换系统类加载器的属性
-Djava.system.class.loader
但是,使用 new (而不是.newInstance())创建的任何类都将AppClassLoader显示为其类加载器。
AppClassLoader也被称为系统类加载器,因此似乎没有任何真正的替换正在进行。
例如,在运行时(Windows JDK 1.8上的Oracle Hotspot)
// Run with java -Djava.system.class.loader=classLoaders.MyClassLoader
public class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class loadClass(String name) throws ClassNotFoundException {
System.out.println("Loading class :" + name);
return super.loadClass(name);
}
};
class A
{
}
public class Example {
public static void main(String[] args) throws Exception {
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(new Example().getClass().getClassLoader());
System.out.println(new A().getClass().getClassLoader());
}
}
输出为
加载类:classLoaders.Example
classLoaders.MyClassLoader@6d06d69c
sun.misc.Launcher$AppClassLoader@58644d46
sun.misc.Launcher$AppClassLoader@58644d46
虽然MyClassLoader加载了Example的第一个实例,而函数GetSystemClassLoader返回了MyClassLoader,但是使用 new 创建的任何类均由原始的System Class Loader加载,因此确切地被替换了?
答案 0 :(得分:1)
您只是扩展ClassLoader并使用super.loadClass();
,因此,其他一些真正的类加载器正在执行实际的类加载。
在后台,在您完成加载工作之后,系统似乎正在委派给System类加载器。
这里已经回答了相同的问题: https://stackoverflow.com/a/25493910/1364747
类加载器L可以通过直接定义C或通过委派来创建C 到另一个类加载器。如果L直接创建C,我们说L 定义C,或者等效地,L是C的定义加载器。
当一个类加载器委托给另一个类加载器时,该加载器 启动加载的不一定是相同的加载器 完成加载并定义类。如果L创建C,则通过 直接或通过委托定义它,我们说L启动加载 C或等效地,L是C的初始加载器。
在运行时,类或接口的确定不仅仅取决于其名称, 但要成对使用:其二进制名称(第4.2.1节)及其定义的类加载器。 每个此类或接口都属于一个运行时包。的 类或接口的运行时包由该包确定 类或接口的名称和定义类加载器。
尽管MyClassLoader调用super.loadClass,但ClassLoader-> loadClass的实现只能找到另一个实例,并委托给它。
因此,父类实现仅将作业传递给其他实例。
答案 1 :(得分:-1)
您应该重写MyClassLoader的toString()方法,看看是否可行。
答案 2 :(得分:-2)
在JVM的非常早的启动顺序中,必须有一个类加载器来加载覆盖该类加载器的类。为此,还必须加载许多其他类,以实现原始类加载器并构建足够的JVM来正确接受重写的类加载器。
成功地重写了类加载器之后,它应该为其余类调用您的重写。
这意味着您必须注意不要将早期的类加载器对未实现版本的调用视为错误。