正如我们所知,当类加载器加载Java类X时,将创建一个文字对象X.class。这个对象(即X.class)是否创建?由“新”操作员创建?它是不是在堆内存上创建的?我试图理解文字对象X.class和它与类加载器的关系,但是弄糊涂了
ssm49v7z1#
假设您正在谈论java.lang.Class对象,它实际上是在本机代码中创建的,并且 * 不 * 使用new运算符。
java.lang.Class
new
如果我们看一下ClassLoader的实现,它使用defineClass方法来创建Class示例,并将其委托给defineClass1和defineClass2。这些方法是native,因此是在原生(非Java)代码中实现的。
ClassLoader
defineClass
Class
defineClass1
defineClass2
native
这发生在ClassLoader.c中,然后重定向到jvm.cpp中的JVM_DefineClassWithSource,然后调用jvm_define_class_common。这引用了一个make_local函数,它在术语中引用了JNIHandleBlock::allocate_handle,它似乎用于Java堆**上的分配。
ClassLoader.c
jvm.cpp
JVM_DefineClassWithSource
jvm_define_class_common
make_local
JNIHandleBlock::allocate_handle
java.lang.Class实际上有一个私有构造函数。然而,这并不被使用,它的存在只是为了欺骗JIT并防止开发人员创建Class示例:不使用此构造函数,它会阻止生成默认构造函数。和
// Initialize final field for classLoader. The initialization value of non-null // prevents future JIT optimizations from assuming this final field is null.
由于构造函数从不使用,因此不能使用new关键字创建。
使用Hotspot,示例创建目前在本机代码中进行。即使它没有使用new关键字,它仍然在Java堆上分配。但是,这部分是特定于JVM的,在其他JVM中可能会有所不同(例如OpenJ9)。
qvsjd97n2#
我们知道,当Java类X被类加载器加载时,将创建一个文本对象X.class。这大致是正确的,但你的术语不正确。所创建的是一个Class对象,而不是一个(类)“文字对象”。字面量是Java源代码中的东西。它在运行时 * 表示 * 一个对象,但它不是对象。这个对象(即X.class)是否创建?Java运行时创建它。当类装入器装入类时,它将装入并记录各种与类相关的信息(描述符、字节码块等)在 * 元空间 * 中。还创建了一个Class对象,作为程序可见的类的运行时表示。加载类、表示它们的元数据和创建Class对象的机制都是特定于实现的。你不需要知道细节…而且它们可能在不同的Java版本之间有所不同。是否由“new”操作符创建?如果你指的是Java new关键字,那么No。创建将(通常)在本机代码中完成。它是不是在堆内存上创建的?这是特定于实现的,但对于当前的实现,答案是肯定的。例如,在Java 17中,java.lang.Class对象是一个堆对象,它是一个名为Klass的本机代码描述符的“java代理”。“你不需要知道这种细节。即使是JNA / JNI程序员也不需要知道jclass是如何实现的。唯一需要知道这一点的人是那些编写和维护JVM代码库的人。(而如果你只是出于好奇而问,我强烈建议你自己做研究;即通过阅读OpenJDK源代码。
X
X.class
Klass
jclass
2条答案
按热度按时间ssm49v7z1#
假设您正在谈论
java.lang.Class
对象,它实际上是在本机代码中创建的,并且 * 不 * 使用new
运算符。查看一下
如果我们看一下
ClassLoader
的实现,它使用defineClass
方法来创建Class
示例,并将其委托给defineClass1
和defineClass2
。这些方法是native
,因此是在原生(非Java)代码中实现的。原生代码
这发生在
ClassLoader.c
中,然后重定向到jvm.cpp
中的JVM_DefineClassWithSource
,然后调用jvm_define_class_common
。这引用了一个
make_local
函数,它在术语中引用了JNIHandleBlock::allocate_handle
,它似乎用于Java堆**上的分配。有一个构造函数
java.lang.Class
实际上有一个私有构造函数。然而,这并不被使用,它的存在只是为了欺骗JIT并防止开发人员创建Class
示例:不使用此构造函数,它会阻止生成默认构造函数。
和
由于构造函数从不使用,因此不能使用
new
关键字创建。总结
使用Hotspot,示例创建目前在本机代码中进行。即使它没有使用
new
关键字,它仍然在Java堆上分配。但是,这部分是特定于JVM的,在其他JVM中可能会有所不同(例如OpenJ9)。
qvsjd97n2#
我们知道,当Java类
X
被类加载器加载时,将创建一个文本对象X.class
。这大致是正确的,但你的术语不正确。所创建的是一个
Class
对象,而不是一个(类)“文字对象”。字面量是Java源代码中的东西。它在运行时 * 表示 * 一个对象,但它不是对象。这个对象(即X.class)是否创建?
Java运行时创建它。当类装入器装入类时,它将装入并记录各种与类相关的信息(描述符、字节码块等)在 * 元空间 * 中。还创建了一个
Class
对象,作为程序可见的类的运行时表示。加载类、表示它们的元数据和创建
Class
对象的机制都是特定于实现的。你不需要知道细节…而且它们可能在不同的Java版本之间有所不同。是否由“new”操作符创建?
如果你指的是Java
new
关键字,那么No。创建将(通常)在本机代码中完成。它是不是在堆内存上创建的?
这是特定于实现的,但对于当前的实现,答案是肯定的。例如,在Java 17中,
java.lang.Class
对象是一个堆对象,它是一个名为Klass
的本机代码描述符的“java代理”。“你不需要知道这种细节。即使是JNA / JNI程序员也不需要知道
jclass
是如何实现的。唯一需要知道这一点的人是那些编写和维护JVM代码库的人。(而如果你只是出于好奇而问,我强烈建议你自己做研究;即通过阅读OpenJDK源代码。