9.5 我们从Java的hello world中学到什么

这是每个Java程序员都知道的程序。这很简单,但是一个简单的开始可以深入复杂的概念。这篇文章中,我将探讨从这个简单的程序中可以学到什么。

HelloWorld.java

public class HelloWorld {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("Hello World");
    }
}

1. 为什么都从一个类开始

Java程序都是从类开始,任何方法和字段都必须在一个类中。这是由于面向对象的特性:一切都是一个类的实例。面向对象编程比函数式编程有很多优点,比如更好的模块化,可扩展性。

2.为什么那总有一个main方法?

main 方法是程序的入口,它是静态的。“static”表示该方法是其类的一部分,而不是对象的一部分。
这是为什么?为什么不把非静态方法作为程序入口?
如果方法不是静态的,那么就需要先创建个对象来使用这个方法,因为必须在对象上调用这个方法。为了入口目的,这不现实的。我们不能得到没有鸡的鸡蛋。因此程序的入口方法是静态的。
参数String [] args 表示可以将一个字符串数组发送到程序来帮助程序初始化。

3.3. HelloWorld的字节码

要执行程序,Java文件首先被编译为存储在.class文件中的java字节码。字节代码是什么样的?字节码本身不可读的。如果我们使用十六进制编辑器,它显示如下:

字节码

我们可以在上面的字节码中看到很多操作码(例如CA、4C等),每个操作码都具有相应的助记码(例如下面的例子的aload_0)。操作码是不可读的。但是我们可以用javap查看.class的助记符形式。(相当于汇编)

“javap -c”打印出类中每个方法的反汇编代码。 反汇编的代码意味着构成Java字节码的指令。

javap -classpath . -c HelloWorld

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"来进一步了解类。

javap -classpath . -verbose HelloWorld

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规范:运行时常量池为编程语言提供类似符号表的函数,虽然它比符号表更宽的数据范围。

“invocationspecial#1”指令中的“#1”指向常量池中的#1常数。 常数是“方法#6.#15;”。 从数字,我们可以递归得到最终的常数。

LineNumberTable向调试器提供信息,以指示哪个Java源代码对应哪个字节码指令。例如,Java源代码中的第9行对应main方法中的字节码0,第10行对应字节码8。
如果你想更多了解字节码,你可以创建和编译一个更复杂的类来看看。Hello world真是这样做的起点。

4.如何在JVM中执行

现在的问题是JVM如何加载类和调用main方法。
在main方法被执行之前,JVM需要1)加载 2)链接 3)初始化类。
1)加载类或接口的二进制形式到JVM中。
2)链接将二进制类型数据并入JVM的运行时状态。

链接包含三个步骤:验证,准备和可选解决方案。验证确保类和接口在结构上是正确的;准备涉及分配类或接口所需的内存;决议解决了符号引用。
3)最后初始化使用适当的初始值分配类变量。

代码执行

通过Java 的ClassLoaders进行加载,当JVM被启动时候,使用三类加载器:
1、Bootstrap class loader:加载位于/jre/lib目录下的java核心类库。它是JVM核心的一部分,用本地代码编写的。
2、Extensions class loader:加载位于扩展目录的代码(比如/jar/lib/ext).
3、System class loader:加载在CLASSPATH中发现的代码。
所以HelloWorld类是由系统类加载器加载的。 当main方法被执行时,它会触发其他依赖类的加载,链接和初始化(如果它们存在)。
最后,将main()框架推入JVM堆栈,并相应地设置程序计数器(PC)。 PC然后指示将println()帧推送到JVM堆栈。 当main()方法完成时,它将从堆栈弹出并执行完成。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容