通过 Java Class Viewer 深入了解 Hello World 应用程序
在二进制(JVM)级别分析“Hello World”应用程序
引言
“Hello World”应用程序是打开编程世界的第一课。在这里,我们描述了“Hello World”应用程序内部的秘密。这将帮助您深入理解Java编程。
“Hello World”应用程序
下面是一个来自Java教程的“Hello World”应用程序示例
/**
* The "Hello World!" Application.
* <p>
* This application comes from:
* http://docs.oracle.com/javase/tutorial/getStarted/cupojava/index.html .
* </p>
*/
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
这是相应类文件HelloWorldApp.class的分析结果
“Hello World”应用程序内部
常量池
常量池是一个结构表,表示类文件中的各种组件,例如字符串
常量、类名和接口名、字段名等。它包括
类
Fieldref
Methodref
InterfaceMethodref
字符串
整数
Float
长整型
双精度浮点型
NameAndType
Utf8
MethodHandle
MethodType
InvokeDynamic
尽管“Hello World
”应用程序非常简单,代码只有一行,但该类的常量池包含34个条目,如下图所示。
下图显示了常量池的提取数据(人类可读格式)。
- 第一部分显示“tag”,即常量池对象的类型。
- 其余部分显示常量池对象的值。
“Hello World!”的文本在哪里?
“Hello World!
”字符串
包含在常量池条目3(tag/type: String
)中,而条目3指向条目23(tag/type: Utf8
)。
方法
尽管HelloWorldApp.java源代码中只定义了一个main方法,但类文件中存在2个方法。
void <init> ()
public static void main (java.lang.String[])
编译时,javac工具生成了一个名为<init>
的方法。
方法:<init>
此方法用于初始化对象。如果类源代码中未定义构造函数,则也会生成<init>
方法。默认情况下,该方法将直接调用java.lang.Object.<init>
方法。
这是该方法的二进制格式源代码,它有5个字节。
2A B7 00 01 B1
这是<init>
方法的提取源代码(技术上可读)。代码采用操作码格式,而Java类查看器则添加了二进制代码的描述。
操作码中有3条命令。
-
aload_0
加载第0个本地变量表,它是Java
Object
实例的引用。在本例中,它从本地变量中加载this
对象。存在与aload_n类似的opcodes指令。
aaload 从数组加载引用。 aload 从本地变量加载引用。 aload_n 从本地变量加载引用。 n
必须是当前帧本地变量数组的索引。baload 从数组加载字节或布尔值。 caload 从数组加载 char
。daload 从数组加载 double
。dload 从本地变量加载 double
。dload_n 从本地变量加载 double
。faload 从数组加载 float
。fload 从本地变量加载 float
。fload_n 从本地变量加载 float
。iaload 从数组加载 int
。iload 从本地变量加载 int
。iload_n 从本地变量加载 int
。laload 从数组加载 long
。lload 从本地变量加载 long
。lload_n 从本地变量加载 long
。saload 从数组加载 short
。 -
invokespecial
调用超类
java.lang.Object
的实例方法<init>
。 -
return
从当前方法返回
void
。
方法:main
这是从源代码编译的main()
方法。
这是该方法的二进制格式源代码,它有9个字节。
B2 00 02 12 03 B6 00 04 B1
这是main()
方法的提取源代码(技术上可读)。代码采用操作码格式,而Java类查看器则添加了二进制代码的描述。
操作码中有4条命令。
-
getstatic
从类
java.lang.System
获取static
字段out
。 -
ldc
将运行时常量池中的条目3推送到堆栈;条目3的tag(类型)是
CONSTANT_String_info
,它引用条目23,其类型为CONSTANT_Utf8_info。如上所述,条目23的值是“
Hello World!
”。 -
invokevirtual
调用实例方法
java.io.PrintStream.println
。 -
return
从当前方法返回
void
。
类的属性
属性在JVM的类文件中用于Class
、Field
、Method
和Code
对象。
在本例中,HelloWorldApp类有一个SourceFile属性。
此属性引用常量池的条目19,其值为“HelloWorldApp.java”,指定当前类的源代码文件名。
历史
- 2014-04-22 - 创建了本文档
- 2014-04-24 - 本文档的第一个版本