`
azvf
  • 浏览: 147104 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

深入理解HelloWord

阅读更多

本文转自http://www.admin10000.com/document/3828.html

深入理解Java HelloWorld






  HelloWorld是每个Java程序员都知道的程序。它很简单,但是简单的开始可以引导你去深入了解更复杂的东西。这篇文章将探究从这个HelloWorld这个简单程序中可以学到的东西。如果你对HelloWorld有独到的理解,欢迎留下你的评论。

  HelloWorld.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class HelloWorld {
 
    /**
     *
     * @param args
     */
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("Hello World");
    }
 
}

 1、为什么一切都是从类开始?

  Java程序是从类开始构建的, 每个方法和字段都必须在类里面。这是由于Java面向对象的特性: 一切都是对象,它是类的一个实例。面向对象编程语言相比函数式编程语言有许多的优势,比如更好的模块化、可扩展性等等。

 2、为什么总有一个“main方法”?

  main方法是程序的入口,并且是静态方法。static关键字意味着这个方法是类的一部分,而不是实例对象的一部分。为什么会这样呢? 为什么我们不用一个非静态的方法作为程序的入口呢?

  如果一个方法不是静态的,那么对象需要先被创建好以后才能使用这个方法。因为这个方法必须要在一个对象上调用。对于一个入口来说,这是不现实的。因此,程序的入口方法是静态的。

  参数 “String[] args”表明可以将一个字符串数组传递给程序来帮助程序初始化。

 3、HelloWorld程序的字节码

  为了执行这个程序,Java文件首先被编译成Java字节码存储到.class文件中。那么字节码看起来是什么样的呢?字节码本身是不可读的,如果我们使用一个二进制编辑器打开,它看起来就像下面那样:

  在上面的字节码中,我们可以看到很多的操作码(比如CA、4C等等),它们中的每一个都有一个对应的助记码(比如下面例子中的aload_0)。操作码是不可读的,但是可以使用javap来查看.class文件的助记形式。

  对于类中的每个方法执行“javap -c”可以输出反汇编代码。反汇编代码即组成Java字节码的指令。

1
javap -classpath .  -c HelloWorld
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Compiled from "HelloWorld.java"
public class HelloWorld extends java.lang.Object{
public HelloWorld();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
  
public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc #3; //String Hello World
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return
}

  上面的代码包含两个方法: 一个是编译器推断出来的默认的构造器;另外一个是main方法。

  接下来,每个方法都有一系列的指令。比如aload_0、invokespecial #1等等。可以在Java字节码指令集中查到每个指令的功能,例如aload_0用来从局部变量0中加载一个引用到堆栈,getstatic用来获取类的一个静态字段值。可以注意到,getstatic指令之后的“#2″指向的是运行期常量池。常量池是JVM运行时数据区之一。我们可以通过“javap -verbose”命令来查看常量池。

  另外, 每个指令从一个数字开始,比如0、1、4等等。在.class文件中,每个方法都有一个对应的字节码数组。这些数字对应于存储每个操作码及其参数的数组的下标。每个操作码都是1个字节长度,并且指令可以有0个或多个参数。这就是为什么这些数字不是连续的原因。

  现在,我们使用“javap -verbose”这个命令来进一步观察这个类。

1
javap -classpath . -verbose HelloWorld
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Compiled from "HelloWorld.java"
public class HelloWorld extends java.lang.Object
  SourceFile: "HelloWorld.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method   #6.#15; //  java/lang/Object."<init>":()V
const #2 = Field    #16.#17;    //  java/lang/System.out:Ljava/io/PrintStream;
const #3 = String   #18;    //  Hello World
const #4 = Method   #19.#20;    //  java/io/PrintStream.println:(Ljava/lang/String;)V
const #5 = class    #21;    //  HelloWorld
const #6 = class    #22;    //  java/lang/Object
const #7 = Asciz    <init>;
const #8 = Asciz    ()V;
const #9 = Asciz    Code;
const #10 = Asciz   LineNumberTable;
const #11 = Asciz   main;
const #12 = Asciz   ([Ljava/lang/String;)V;
const #13 = Asciz   SourceFile;
const #14 = Asciz   HelloWorld.java;
const #15 = NameAndType #7:#8;//  "<init>":()V
const #16 = class   #23;    //  java/lang/System
const #17 = NameAndType #24:#25;//  out:Ljava/io/PrintStream;
const #18 = Asciz   Hello World;
const #19 = class   #26;    //  java/io/PrintStream
const #20 = NameAndType #27:#28;//  println:(Ljava/lang/String;)V
const #21 = Asciz   HelloWorld;
const #22 = Asciz   java/lang/Object;
const #23 = Asciz   java/lang/System;
const #24 = Asciz   out;
const #25 = Asciz   Ljava/io/PrintStream;;
const #26 = Asciz   java/io/PrintStream;
const #27 = Asciz   println;
const #28 = Asciz   (Ljava/lang/String;)V;
  
{
public HelloWorld();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable:
   line 2: 0
  
  
public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc #3; //String Hello World
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return
  LineNumberTable:
   line 9: 0
   line 10: 8
}

  引用JVM规范中的描述:运行期常量池提供的功能类似传统编程语言的符号表所起作用, 尽管它比传统的符号表包含的内容更广范。

  “invokespecial #1″指令中的“#1″指向常量池中的#1常量。这个常量是 “Method #6.#15;”。通过这个数字,我们可以递归地得到最终的常量。

  LineNumberTable为调试器提供了用来指示Java源代码与字节码指令之间的对应信息。例如,Java源代码中的第9行对应于main方法中的字节码0,并且第10行对应于字节码8。

  如果想要了解更多关于字节码的内容,可以创建一个更加复杂的类进行编译和查看,HelloWorld真的只是一个开始。

 4、HelloWorld在JVM中是如何执行的?

  现在的问题是JVM是怎样加载这个类并调用main方法?

  在main方法执行之前, JVM需要加载链接以及初始化这个类。

  1. 加载将类/接口的二进制形式装入JVM中。

  2. 链接将二进制类型的数据融入到JVM的运行时。链接由3个步骤组成:验证、准备、以及解析(可选)。验证确保类、接口在结构上是正确的;准备涉及到为类、接口分配所需要的内存;解析是解析符号引用。

  3. 最后,初始化为类变量分配正确的初始值。

  加载工作是由Java类加载器来完成的。当JVM启动时,会使用下面三个类加载器:

  1. Bootstrap类加载器:加载位于/jre/lib目录下的核心Java类库。它是JVM核心的一部分,并且使用本地代码编写。
  2. 扩展类加载器:加载扩展目录中的代码(比如/jar/lib/ext)。
  3. 系统类加载器:加载在CLASSPATH上的代码。

  所以,HelloWorld类是由系统加载器加载的。当main方法执行时,它会触发加载其它依赖的类,进行链接和初始化。前提是它们已经存在。

  最后,main()帧被压入JVM堆栈,并且程序计数器(PC)也进行了相应的设置。然后,PC指示将println()帧压入JVM堆栈栈顶。当main()方法执行完毕会被弹出堆栈,至此执行过程就结束了。

 参考文档

  1. 加载
  2. 类加载机制
  3. 类加载器
分享到:
评论

相关推荐

    helloword

    理解源码对于学习编程至关重要,因为它揭示了程序的工作原理。 "工具" 这个标签可能意味着文章讨论了与编写、编辑、编译或运行 "HelloWord" 相关的工具,比如文本编辑器(如Visual Studio Code、Notepad++)、集成...

    HelloWord.zip

    这为开发者提供了更大的市场潜力,但同时也要求开发者对不同平台的交互设计有深入理解。 在探索"HelloWord.zip"中的项目时,我们可以结合博客内容深入学习Xcode 11.1的新特性,逐步掌握Swift编程和iOS应用开发的...

    HelloWord.rar

    【标题】"HelloWord.rar" 是一个压缩包文件,它包含了一个C#编程...总的来说,"HelloWord.rar"提供了一个很好的学习机会,通过研究这个源码,你可以深入理解C#编程和串口通信技术,同时也可以提高你的软件开发能力。

    hibernate3.2之helloword

    源码分析有助于开发者深入理解Hibernate内部机制,而工具部分则可能涵盖如何使用Eclipse、IntelliJ IDEA等IDE进行高效开发。 【文件名称列表】中的"Hibernate1"可能代表一系列教程文件的首部分,可能包含如下内容:...

    Helloword.rar

    在Python编程语言的世界里,"Hello, World!" 是一个经典的起点,它标志着你的编程旅程的开始。...通过这些基础练习,你可以逐步建立起对Python语法和编程思维的理解,为进一步深入学习打下坚实的基础。

    android helloword

    在Android开发领域,"Hello, World!"是每个初学者入门时的第一个程序,它标志着开发者向Android编程世界的...随着对Android框架的深入学习,开发者将能够创建功能丰富的应用程序,服务于全球数亿的Android设备用户。

    mybatis的helloword程序代码

    首先,我们需要理解MyBatis的核心组成部分:SqlSessionFactory、SqlSession和Mapper接口。SqlSessionFactory是MyBatis的入口点,它负责创建SqlSession对象,而SqlSession则是执行SQL语句的接口。Mapper接口则用于...

    struts2 helloword工程

    Struts2是一个强大的MVC(Model-View-Controller)框架,...随着对Struts2框架的深入学习,你可以了解更多的功能,如拦截器、结果类型、OGNL表达式、动态方法调用等,这些将帮助你构建更复杂、更健壮的企业级Web应用。

    黑莓开发helloword

    本主题“黑莓开发HelloWord”旨在引导开发者了解如何在黑莓平台上创建一个简单的“Hello, World!”应用,这是所有编程语言入门的标志性练习。通过这个过程,我们可以学习到基础的黑莓开发环境搭建、开发工具的使用,...

    VC++.NET编程实例(HelloWord)

    首先,让我们了解什么是VC++.NET。VC++.NET是微软开发的一种集成开发环境(IDE),用于编写使用C++编程语言的应用程序。它集成了.NET Framework,这是一个用于构建和运行托管代码的平台,提供了丰富的类库和服务。 ...

    Struts2: HelloWord

    这个例子通常帮助开发者了解如何在Struts2框架下设置基本的配置并展示一个简单的页面。 首先,我们需要理解Struts2的核心组件。`struts2-core-2.2.1.1.jar`是Struts2框架的核心库,包含了框架的控制器、拦截器、...

    HelloWord WDM驱动开发

    这些文件是实践WDM驱动开发的关键,通过分析和运行这些代码,你可以深入理解驱动程序的工作原理和开发流程。 总的来说,"HelloWord WDM驱动开发"是一个基础但重要的学习课题,它将带你进入驱动开发的世界,帮助你...

    visual studio2008C# Helloword运行代码

    初学者通过对比这两个语言的Hello, World程序,可以初步了解它们的语法特点和开发环境的不同,为后续深入学习打下基础。在Visual Studio 2008中实践C#编程,结合对Java的理解,将有助于拓展编程视野,提升编程技能。

    php项目helloword

    这个项目对于想要深入理解PHP后端开发和数据库管理的初学者来说,是一个很好的起点。 首先,我们要了解PHP,这是一种广泛使用的开源脚本语言,尤其适用于Web开发,可以嵌入到HTML中使用。PHP语法简洁,学习曲线相对...

    Spring MVC Helloword代码

    Spring MVC 是一个基于Java的...随着你对Spring MVC的深入学习,你可以了解到更多高级特性,如数据验证、国际化、异常处理、Ajax支持、RESTful API设计等。这只是一个起点,Spring MVC的强大功能等待着你去探索和利用。

    Merapi 的helloword例子

    5. **参考网址.txt**:这个文件可能提供了关于Merapi的官方文档链接或其他学习资源,帮助开发者更深入地了解Merapi的工作原理和用法。 6. **helloworld**:这个文件可能是示例的源代码,包括AIR客户端的Flex或...

    springmvc之HelloWord

    通过这个基础的"HelloWord"实例,你已经迈出了学习和理解Spring MVC的第一步。继续深入,你可以学习更多高级特性,如模型-视图-适配器(MVP)模式、数据绑定、拦截器、异常处理等,从而构建更复杂的企业级Web应用。

    STRUTS2HELLOWORD

    Struts2HelloWorld是一个经典的入门教程,旨在帮助初学者理解并...随着对框架的深入理解,开发者可以逐步探索更高级的功能,如OGNL表达式、动态方法调用、插件机制等,从而更好地利用Struts2进行复杂Web应用的开发。

    helloword入门系列之swing 入门 简单的桌面小词典—附

    通过阅读和理解代码,你可以更深入地学习Swing的用法,包括组件的创建、布局的设置以及事件监听器的实现。同时,这也是一个很好的实践机会,可以帮助你巩固Swing相关的知识。 总之,Swing是Java GUI编程的强大工具...

    Android环境搭配及简单HelloWord.doc

    这篇教程的重要性在于它为新手提供了入门Android开发的起点,帮助他们理解Android开发的基本流程。 首先,Android环境的搭建是Android应用开发的首要步骤。这通常包括安装Java Development Kit (JDK),设置Java环境...

Global site tag (gtag.js) - Google Analytics