什么加载java系统类加载器?

什么加载java系统类加载器?,java,classloader,Java,Classloader,我们知道,我们可以通过以下方式覆盖系统: 那么,既然com.test.MyClassLoader本身就是一个类,那么它是由谁加载的呢 我们如何从Javadoc获取这个“元”类加载器的类文件 如果在首次调用此方法时定义了系统属性“java.system.class.loader”,则该属性的值将被视为将作为系统类装入器返回的类的名称使用默认系统类加载器加载该类,并且必须定义一个公共构造函数,该构造函数采用ClassLoader类型的单个参数作为委托父级 默认系统类加载器本身特定于JVM实现。引导类

我们知道,我们可以通过以下方式覆盖系统:

那么,既然
com.test.MyClassLoader
本身就是一个类,那么它是由谁加载的呢

我们如何从Javadoc获取这个“元”类加载器的类文件

如果在首次调用此方法时定义了系统属性“java.system.class.loader”,则该属性的值将被视为将作为系统类装入器返回的类的名称使用默认系统类加载器加载该类,并且必须定义一个公共构造函数,该构造函数采用ClassLoader类型的单个参数作为委托父级


默认系统类加载器本身特定于JVM实现。

引导类加载器
是所有
类加载器的父类
,并在JRE的lib目录(rt.jar和i18n.jar)中加载标准JDK类。所有java.*类都由这个
classloader
加载

扩展类加载器
是引导类加载器的直接子级。此类加载器加载JRE的lib\ext目录中的类

系统类路径类加载器
是扩展类加载器的直接子级。它加载
CLASSPATH
环境变量指定的类和JAR

您可以尝试通过“java.system.class.loader”属性注入自定义类加载器(请参阅)

默认系统类加载器
是MyClassLoader实例的父级,

Tldr: ..该属性的值被视为将作为系统类装入器返回的类的名称。使用默认系统类加载器加载该类

…因此,如果类加载器将X替换为系统类加载器,那么类加载器的父级将是X,默认的系统类加载器

(X的类型类似于。)

有关更多信息,请访问:

Java启动器Java启动Java虚拟机。这个 虚拟机按以下顺序搜索和加载类:

引导类——构成Java平台的类,包括rt.jar中的类和其他几个重要的jar文件

扩展类——使用Java扩展机制的类。这些文件作为.jar文件捆绑在extensions目录中

用户类——由开发人员和第三方定义的类,它们不利用扩展机制。你确定 使用上的-classpath选项显示这些类的位置 命令行或使用CLASSPATH环境变量

Tsmr: 我们可以证明X确实是我们的父母:

这是我们的主要代码:

public class Main {
    public static void main(String args[]) {
        System.out.println("getSystemClassLoader(): " + ClassLoader.getSystemClassLoader());

        ClassLoader cl = MyCL.class.getClassLoader();
        System.out.println("Classloader of MyCL: " + cl);

        Class type_of_cl = cl.getClass();
        System.out.println("..and its type: " + type_of_cl);

        ClassLoader cl_of_cl = class_of_cl.getClassLoader();
        System.out.println("Classloader of (Classloader of MyCL): " + cl_of_cl);
    }
}
这是使用命令java-Djava.system.class.loader=MyCL Main运行时的输出(在我的系统上)(参见):

getSystemClassLoader():MyCL@1888759
MyCL的类加载器:sun.misc.Launcher$AppClassLoader@7fdcde
…及其类型:class sun.misc.Launcher$AppClassLoader
的类加载器(MyCL的类加载器):null

我们可以看到
MyCL
的类加载器是,这是默认的系统类加载器


(根据上面Oracle的另一段引文中所述的语言,默认系统类加载器也被称为“用户类的类加载器。请不要担心Oracle会为同一事物提供两个名称。)

合适的答案是:

这也澄清了原来的问题

当你这样做的时候

java-Djava.system.class.loader=com.test.MyClassLoader xxx

-D选项用于在java.lang.system实例的properties对象中设置系统属性,该实例作为JVM启动的一部分加载。该选项仅更改内存中的属性。在下一次调用类XXX或其他一些类时,将再次加载作为系统类一部分的默认属性。在这里,您已经将java.system.class.loader属性设置为值com.test.MyClassLoader。换句话说,对于类XXX的调用,您希望使用新的系统类加载器覆盖默认的系统类加载器(也称为引导类加载器)。作为JVM启动的一部分加载的默认系统类加载器将查找内存中的java.system.class.loader属性,以查找覆盖系统类加载器的名称——如果设置为(在本例中,设置为MyClassLoader)——并从类路径(默认情况下,是工作目录的根目录)加载它(应该包含XXX)或类路径变量中的一个,如定义为-cp或环境变量classpath

如果你写的是你的类XXX的主方法

    System.out.println(ClassLoader.getSystemClassLoader());
    System.out.println(MyClassLoader.class.getClassLoader());
你应该看到

  MyClassLoader      
(加载XXX的新系统类加载器)


(加载新系统类加载器的默认系统类加载器)

因此,我们的
com.test.MyClassLoader
的父级是默认的系统类加载器?默认的系统类加载器仍然被使用?即使我们重写了系统类加载器?@James.Xu:是的,父级仍然是默认的系统类加载器,但是您可以总是重写
loadClass
实现来绕过它。请参阅有关如何使用代码而不是cmd设置执行此操作的详细信息。始终首先参考文档,每次在SO中阅读正确答案时,我都会重新学习这些内容。引导加载本身和其他加载—“有趣”边缘大小写:在自定义系统
ClassLoader
MySysCl
下,不将应用程序类路径类的加载委托给其父级
MySysCl.class.getClassLoader().getClass().equals(ClassLoader.getSystemClassLoader().getClass())==true
    System.out.println(ClassLoader.getSystemClassLoader());
    System.out.println(MyClassLoader.class.getClassLoader());
  MyClassLoader      
 sun.misc.Launcher$AppClassLoader