以下是该计划:
package annotationtype;
public class Example {
public static void main(String[] args){
}
}
使用以下字节代码编译。
Classfile /D:/git/Java_programming/JavaCode/bin/annotationtype/Example.class
......
Compiled from "Example.java"
public class annotationtype.Example
.......
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // annotationtype/Example
#2 = Utf8 annotationtype/Example
#3 = Class #4 // java/lang/Object
......
#18 = Utf8 SourceFile
#19 = Utf8 Example.java
{
public annotationtype.Example();
........
public static void main(java.lang.String[]);
......
}
SourceFile: "Example.java"
使用eclipse编辑器,在main()
方法中,如果我输入,
Example.
,eclipse编辑器立即提供class
类型的Class<annotationtype.Example>
成员
我的理解是,
低于字节代码,
#1 = Class #2 // annotationtype/Example
..
#3 = Class #4 // java/lang/Object
表示在Class<annotationtype.Example>
的初始化阶段创建成员Class<annotationtype.Example> class
所指向的class Example
类型的对象,在功能上等同于:
public class annotationtype.Example{
public static Class<annotationtype.Example> class;
{
class = Class.forName("annotationtype.Example")
}
......
}
我的理解是否正确,
Class<annotationtype.Example>
类型的对象(创建)出现的阶段,Example.class
指向的阶段?
答案 0 :(得分:9)
您将Java编程语言的工件与包含Java字节代码的类文件的常量池项混淆。
type.class
形式的类文字,以及对array.length
形式数组长度的访问可能看起来像源代码中的成员访问,但与真实无关班级成员。
E.g。当您编写array.length
时,它将被编译为字节码指令arraylength
,专用于在运行时检索数组的长度,而无需实际指定JVM如何记住数组的长度。这取决于实现。
类文字更复杂。例如。当你写int.class
时,没有什么可查询的。相反,编译器知道它必须读取static
字段Integer.TYPE
以获取运行时值以及该类文字的编译方式,作为对Integer.TYPE
的字段访问。相比之下,引用类型的类文字是使用ldc
指令编译的,该指令指向与字段无关的常量池条目。
类的常量池首先不包含Java对象。它包含链接信息。某些条目可能在首次使用时与Java运行时实例关联,但其工作方式是故意未指定的。这取决于JVM。这些条目用于不同的目的,即类条目可用于指定超类,实现的接口或类,其成员可通过方法调用或字段访问来访问。
这就是你的Example
类文件包含这样一个Class条目的原因。它就在那里,因为该类使用它来描述自己。即使根本没有类文字Example.class
。因此,描述类Class
的{{1}}实例是创建when the class is loaded。 Example
会记住所有已加载的类,并且在使用相同的加载器解析相同的名称时将使用它们。
请注意,当另一个类包含ClassLoader
形式的类文字时,它将在其自己的常量池中拥有该类的自己的Class条目。类文本的运行时评估可以触发加载,从而在以前未加载时创建Example.class
实例。否则,它将通过类加载器解析为已加载的类。