Java 为什么findLoadedClass方法调用返回不同的结果?;

Java 为什么findLoadedClass方法调用返回不同的结果?;,java,classloader,Java,Classloader,考虑一个自定义类加载器类CustomClassLoader扩展类加载器 如果我调用loadClass,如下所示 ClassLoader loader = new ClassLoader(){}; loader.loadClass("java.util.ArrayList"); Method method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); method.setAccessible(tru

考虑一个自定义类加载器
类CustomClassLoader扩展类加载器

如果我调用
loadClass
,如下所示

ClassLoader loader = new ClassLoader(){}; 
loader.loadClass("java.util.ArrayList");
Method method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
method.setAccessible(true);
System.out.println(method.invoke(loader,"java.util.ArrayList"));
它输出
null

但如果我替换

loader.loadClass("java.util.ArrayList"); 

它输出
类java.util.ArrayList


有人能解释这个问题吗?

默认的
ClassLoader
实现按以下顺序执行类加载:

  • 调用findLoadedClass(字符串)检查该类是否已 已加载
  • 在父类加载器上调用loadClass方法。如果父级为null,则虚拟机内置的类加载器为空 而是用了
  • 调用findClass(String)方法来查找该类
  • 这是一个直接摘录自

    当您调用
    loadClass
    时,您的实现将在尝试加载父类加载器之前委托给父类加载器。这恰好是您的系统类装入器

    在本例中,您的类已经在系统类加载器的类路径上,因此它被加载

    稍后调用
    findLoadedClass
    时,该方法仅检查指定的类加载器是否已加载该类。它不执行进一步的授权

    调用
    method.invoke(loader,“java.util.ArrayList”)
    时,您试图在
    CustomerClassLoader
    中找到加载的类。这会失败,因为执行加载的是父类加载器

    您可以通过调用系统类加载器上的方法来证明这一点,如下所示:

    method.invoke(ClassLoader.getSystemClassLoader(),"java.util.ArrayList")
    

    默认的
    ClassLoader
    实现按以下顺序执行类加载:

  • 调用findLoadedClass(字符串)检查该类是否已 已加载
  • 在父类加载器上调用loadClass方法。如果父级为null,则虚拟机内置的类加载器为空 而是用了
  • 调用findClass(String)方法来查找该类
  • 这是一个直接摘录自

    当您调用
    loadClass
    时,您的实现将在尝试加载父类加载器之前委托给父类加载器。这恰好是您的系统类装入器

    在本例中,您的类已经在系统类加载器的类路径上,因此它被加载

    稍后调用
    findLoadedClass
    时,该方法仅检查指定的类加载器是否已加载该类。它不执行进一步的授权

    调用
    method.invoke(loader,“java.util.ArrayList”)
    时,您试图在
    CustomerClassLoader
    中找到加载的类。这会失败,因为执行加载的是父类加载器

    您可以通过调用系统类加载器上的方法来证明这一点,如下所示:

    method.invoke(ClassLoader.getSystemClassLoader(),"java.util.ArrayList")
    

    什么是
    CustomClassLoader
    ?由于我们不知道该类是什么以及它是做什么的,所以不可能知道它的
    findLoadedClass
    方法是做什么的。我相信
    findLoadedClass
    只检查
    ClassLoader
    是否加载了该类,它不会委托给其父类。由于
    ArrayList
    是一个核心类,它不是由您的自定义
    ClassLoader
    @Jesper CustomClassLoader加载的,它只是扩展了ClassLoader并继承了ClassLoader的方法。findLoadedClass方法是由ClassLoader提供的,所以您只需编写
    ClassLoader=new ClassLoader(){}
    ?@matt我能想到的唯一一件事是
    findLoadedClass
    的文档说(我的重点):“如果Java虚拟机已将此加载程序记录为具有该二进制名称的类的初始加载程序,则返回具有给定二进制名称的类。否则返回null”。启动加载器的定义似乎是。我猜
    Class#forName(String,boolean,ClassLoader)
    使指定的
    ClassLoader
    成为“启动加载器”。什么是
    CustomClassLoader
    ?由于我们不知道该类是什么以及它是做什么的,所以不可能知道它的
    findLoadedClass
    方法是做什么的。我相信
    findLoadedClass
    只检查
    ClassLoader
    是否加载了该类,它不会委托给其父类。由于
    ArrayList
    是一个核心类,它不是由您的自定义
    ClassLoader
    @Jesper CustomClassLoader加载的,它只是扩展了ClassLoader并继承了ClassLoader的方法。findLoadedClass方法是由ClassLoader提供的,所以您只需编写
    ClassLoader=new ClassLoader(){}
    ?@matt我能想到的唯一一件事是
    findLoadedClass
    的文档说(我的重点):“如果Java虚拟机已将此加载程序记录为具有该二进制名称的类的初始加载程序,则返回具有给定二进制名称的类。否则返回null”。启动加载器的定义似乎是。我猜
    Class#forName(String,boolean,ClassLoader)
    会使指定的
    ClassLoader
    成为“启动加载器”。但是如果我将“loader.loadeclass”(“java.util.ArrayList”);”替换为“Class.forName”(“java.util.ArrayList”),则它会输出“Class java.util.ArrayList”“你怎么解释这件事呢?”安萱我不知道你在问什么。我想我已经解释过了。如果可能,对
    loader.loadClass
    的调用将加载到
    loader
    的父类加载器上。对
    Class.forName
    的调用将仅在给定的类加载器上加载。这是因为两个不同的调用导致了两种不同的类加载机制。另外,您有什么参考说明该类将仅在给定的类加载器上加载?当您调用
    类时