Hello World程序的由來(lái)
Hello World是一個(gè)最著名的程序闺兢。對(duì)每一位程序員來(lái)說(shuō),這個(gè)程序幾乎是每一門(mén)編程語(yǔ)言中的第一個(gè)示例程序戏罢。Hello World最早是由 Brian Kernighan 創(chuàng)建的列敲。1978年,Brian Kernighan寫(xiě)了一本名叫《C程序設(shè)計(jì)語(yǔ)言》的編程書(shū)帖汞,在程序員中廣為流傳戴而。當(dāng)他被問(wèn)及為什么選擇『Hello, World!』時(shí),他回答說(shuō)翩蘸,『我只記得所意,我好像看過(guò)一幅漫畫(huà),講述一枚雞蛋和一只小雞的故事催首,在那副漫畫(huà)中扶踊,小雞說(shuō)了一句‘Hello World’』。
Hello World
Hello World是我們學(xué)習(xí)java的第一個(gè)程序郎任,簡(jiǎn)單的再也不能簡(jiǎn)單了秧耗,可是里面的原理以及執(zhí)行流程大家都知道嗎?最近特地鉆研了一番分享給大家舶治!
貼出Hello World的代碼如下:
public class HelloWorld { ? ? ? ? ? ? ? ? ? ? ? ?
?public static void main(String[] args) ?
?{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? String s ; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? s = “Hello World!”; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? System.out.println(s); ? ? ? ? ? ? ? ? ? ? ? ?
?} ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
}
分析內(nèi)存圖:
Hello World的具體執(zhí)行過(guò)程
1.執(zhí)行HelloWorld.java文件分井,生成HelloWorld.class字節(jié)碼文件;
2.虛擬機(jī)執(zhí)行HelloWorld.class霉猛,將這個(gè)類(lèi)加載到內(nèi)存中(即方法區(qū)的類(lèi)代碼區(qū)中)尺锚;
3. 虛擬機(jī)通過(guò)類(lèi)找到HelloWorld的主方法(程序的入口方法),訪問(wèn)權(quán)限為public(公有可用)惜浅,虛擬機(jī)傳遞String[](字符串?dāng)?shù)組對(duì)象:空數(shù)組)類(lèi)型參數(shù)的地址到主方法的args中去瘫辩,并在棧區(qū)為args開(kāi)辟內(nèi)存空間,返回一個(gè)void的返回值坛悉;
4.定義一個(gè)String(標(biāo)準(zhǔn)類(lèi)庫(kù)中的)類(lèi)型的變量(在棧區(qū)開(kāi)辟空間)s伐厌,s的值不確定(垃圾值,編譯無(wú)法通過(guò))裸影;
5. s = “Hello World!”挣轨,對(duì)象“Hello World!”在方法區(qū)的常量數(shù)據(jù)區(qū)開(kāi)辟空間,屬性即為:Hello World!空民,方法即為:toString()刃唐,變量s存放對(duì)象“Hello World!”的地址;
6. 虛擬機(jī)找到標(biāo)準(zhǔn)類(lèi)庫(kù)中的System.class類(lèi)并加載到內(nèi)存中(即方法區(qū)的類(lèi)代碼區(qū)中)界轩,System.out為標(biāo)準(zhǔn)字節(jié)輸出流對(duì)象()画饥,并調(diào)用println()方法將變量s的值打印到屏幕上。
PS: 虛擬機(jī)調(diào)用主方法時(shí)會(huì)創(chuàng)建三個(gè)默認(rèn)對(duì)象:System.out(標(biāo)準(zhǔn)字節(jié)輸出流對(duì)象)浊猾、System.in(標(biāo)準(zhǔn)字節(jié)輸入流對(duì)象)和System.error(標(biāo)準(zhǔn)字節(jié)出錯(cuò)流對(duì)象).
以上共涉及:
1個(gè)java文件:HelloWorld.java
4個(gè)class類(lèi): HelloWorld.class抖甘、String[].class、String.class葫慎、System.class
5個(gè)對(duì)象: “Hello World!”衔彻、String[]、System.out偷办、System.in艰额、System.error
2個(gè)變量:args、s
3個(gè)方法:main()椒涯、toString()柄沮、println()
為什么一切都是從類(lèi)開(kāi)始?
Java程序是從類(lèi)開(kāi)始構(gòu)建的, 每個(gè)方法和字段都必須在類(lèi)里面废岂。這是由于Java面向?qū)ο蟮奶匦? 一切都是對(duì)象祖搓,它是類(lèi)的一個(gè)實(shí)例。面向?qū)ο缶幊陶Z(yǔ)言相比函數(shù)式編程語(yǔ)言有許多的優(yōu)勢(shì)湖苞,比如更好的模塊化拯欧、可擴(kuò)展性等等。
為什么總有一個(gè)“main方法”财骨?
main方法是程序的入口镐作,并且是靜態(tài)方法。static關(guān)鍵字意味著這個(gè)方法是類(lèi)的一部分隆箩,而不是實(shí)例對(duì)象的一部分滑肉。為什么會(huì)這樣呢? 為什么我們不用一個(gè)非靜態(tài)的方法作為程序的入口呢?
如果一個(gè)方法不是靜態(tài)的摘仅,那么對(duì)象需要先被創(chuàng)建好以后才能使用這個(gè)方法靶庙。因?yàn)檫@個(gè)方法必須要在一個(gè)對(duì)象上調(diào)用。對(duì)于一個(gè)入口來(lái)說(shuō)娃属,這是不現(xiàn)實(shí)的六荒。因此,程序的入口方法是靜態(tài)的矾端。
參數(shù) “String[] args”表明可以將一個(gè)字符串?dāng)?shù)組傳遞給程序來(lái)幫助程序初始化掏击。
HelloWorld在JVM中是如何執(zhí)行的?
現(xiàn)在的問(wèn)題是JVM是怎樣加載這個(gè)類(lèi)并調(diào)用main方法秩铆?
在main方法執(zhí)行之前, JVM需要加載砚亭、鏈接以及初始化這個(gè)類(lèi)灯变。
1. 加載將類(lèi)/接口的二進(jìn)制形式裝入JVM中。
2. 鏈接將二進(jìn)制類(lèi)型的數(shù)據(jù)融入到JVM的運(yùn)行時(shí)捅膘。鏈接由3個(gè)步驟組成:驗(yàn)證添祸、準(zhǔn)備、以及解析(可選)寻仗。驗(yàn)證確保類(lèi)刃泌、接口在結(jié)構(gòu)上是正確的;準(zhǔn)備涉及到為類(lèi)署尤、接口分配所需要的內(nèi)存耙替;解析是解析符號(hào)引用。
3. 最后,初始化為類(lèi)變量分配正確的初始值。
加載工作是由Java類(lèi)加載器來(lái)完成的阴颖。當(dāng)JVM啟動(dòng)時(shí)纯衍,會(huì)使用下面三個(gè)類(lèi)加載器:
Bootstrap類(lèi)加載器:加載位于/jre/lib目錄下的核心Java類(lèi)庫(kù)。它是JVM核心的一部分,并且使用本地代碼編寫(xiě)。
擴(kuò)展類(lèi)加載器:加載擴(kuò)展目錄中的代碼(比如/jar/lib/ext)。
系統(tǒng)類(lèi)加載器:加載在CLASSPATH上的代碼啥酱。
所以,HelloWorld類(lèi)是由系統(tǒng)加載器加載的厨诸。當(dāng)main方法執(zhí)行時(shí)镶殷,它會(huì)觸發(fā)加載其它依賴(lài)的類(lèi),進(jìn)行鏈接和初始化微酬。前提是它們已經(jīng)存在绘趋。
最后,main()幀被壓入JVM堆棧颗管,并且程序計(jì)數(shù)器(PC)也進(jìn)行了相應(yīng)的設(shè)置陷遮。然后,PC指示將println()幀壓入JVM堆棧棧頂垦江。當(dāng)main()方法執(zhí)行完畢會(huì)被彈出堆棧帽馋,至此執(zhí)行過(guò)程就結(jié)束了。