65.9K
CodeProject 正在变化。 阅读更多。
Home

通过 Java Class Viewer 深入了解 Hello World 应用程序

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2014 年 4 月 24 日

MIT

4分钟阅读

viewsIcon

20908

downloadIcon

280

在二进制(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个条目,如下图所示。

下图显示了常量池的提取数据(人类可读格式)。

  1. 第一部分显示“tag”,即常量池对象的类型。
  2. 其余部分显示常量池对象的值。
“Hello World!”的文本在哪里?

Hello World!字符串包含在常量池条目3(tag/type: String)中,而条目3指向条目23(tag/type: Utf8)。

方法

尽管HelloWorldApp.java源代码中只定义了一个main方法,但类文件中存在2个方法。

  1. void <init> ()
  2. public static void main (java.lang.String[])

编译时,javac工具生成了一个名为<init>的方法。

方法:<init>

此方法用于初始化对象。如果类源代码中未定义构造函数,则也会生成<init>方法。默认情况下,该方法将直接调用java.lang.Object.<init>方法。

这是该方法的二进制格式源代码,它有5个字节。

 2A  B7  00  01  B1 

这是<init>方法的提取源代码(技术上可读)。代码采用操作码格式,而Java类查看器则添加了二进制代码的描述。

操作码中有3条命令。

  1. aload_0

    加载第0个本地变量表,它是JavaObject实例的引用。在本例中,它从本地变量中加载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
  2. invokespecial

    调用超类java.lang.Object的实例方法<init>

  3. return

    从当前方法返回void

方法:main

这是从源代码编译的main()方法。

这是该方法的二进制格式源代码,它有9个字节。

 B2  00  02  12  03  B6  00  04  B1 

这是main()方法的提取源代码(技术上可读)。代码采用操作码格式,而Java类查看器则添加了二进制代码的描述。

操作码中有4条命令。

  1. getstatic

    从类java.lang.System获取static字段out

  2. ldc

    将运行时常量池中的条目3推送到堆栈;条目3的tag(类型)是CONSTANT_String_info,它引用条目23,其类型为CONSTANT_Utf8_info

    如上所述,条目23的值是“Hello World!”。

  3. invokevirtual

    调用实例方法java.io.PrintStream.println

  4. return

    从当前方法返回void

类的属性

属性在JVM的类文件中用于ClassFieldMethodCode对象。

在本例中,HelloWorldApp类有一个SourceFile属性。

此属性引用常量池的条目19,其值为“HelloWorldApp.java”,指定当前类的源代码文件名。

历史

  • 2014-04-22 - 创建了本文档
  • 2014-04-24 - 本文档的第一个版本
© . All rights reserved.