谁在 class-loading 过程中首先创建了 Class<?> 对象?

Who firstly creates Class<?> object during class-loading process?

documentation 我发现:

Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.

我检查了 the source code,但没有找到要调用的地方 defineClass 例如从 loadClass 方法。 请告诉我谁以及何时根据此方案调用 defineClass 方法:

图片source

defineClass()方法在调用ClassLoader#loadClass()的过程中被调用。但是,这不是直接在 java.lang.ClassLoader class 中完成的,而是在其子 class 之一中完成的,例如在 URLClassLoader#findClass().

ClassLoader#defineClass() 的调用以对 native 方法之一的调用结束 defineClass1() or defineClass2(). The C implementations of these methods can be found in OpenJDK in src/share/native/java/lang/ClassLoader.c.

java.lang.ClassLoader这么大class。使用您的 GrepCode link( 用于 java 6-b14 版本 ),您可以在第 267 行找到 public loadClass 方法.

此方法在第 308 行调用受保护的 loadClass 方法,此方法尝试使用以下方法加载先前加载的 class:

  • findLoadedClass 最终调用 Native 方法,
  • 呼叫parent.loadClass,
  • findBootstrapClass0(一个native方法也是)如果没有parent,
  • 最后 findClass 如果没有找到 class。

这一点很重要,因为 ClassLoader 会尝试重用已加载的类,请记住。

但是,defineClass 在哪里调用?这个摘要没有地方 class,但是如果你使用 GrepCode 的参考工具并搜索它被使用的地方 defineClass (see here results) 你会发现很多具体的 classes最后调用 definClass.

这并不简单,其中一些 class 会覆盖 defineClass 而其他人会调用自己的 loadClass 然后调用 ... 等等,但最终它会调用defineClass.

不要忘记 ClassLoaderdefineClass 以负责 JVM magic 的三个本机方法之一结束:defineClass0 , defineClass1 and/or defineClass2

编辑

本机函数 defineClass0ClassLoader.c 调用 Java_java_lang_ClassLoader_defineClass0,函数 1 和函数 2 也是如此。

此函数使用 jvm.h 中定义并在 openjdk\hotspot\src\share\vm\prims\jvm.cpp 中实现的 JVM_DefineClassWithSource 创建所需的 class。

最后一个文件定义了 jvm_define_class_common 函数,它最终是创建所需 class 的函数。最后,这个函数调用 JNIHandles::make_local 来分配 class。您可以在 openjdk\hotspot\src\share\vm\runtime\jniHandles.cpp

中查看最后一个函数的代码

希望它能回答您的问题。

class NetworkClassLoader extends ClassLoader {
         String host;
         int port;

         public Class findClass(String name) {
             byte[] b = loadClassData(name);
             return defineClass(name, b, 0, b.length);
         }

         private byte[] loadClassData(String name) {
             // load the class data from the connection
              . . .
         }
     }