Java程序從源文件創(chuàng)建到程序運(yùn)行要經(jīng)過(guò)兩大步驟:1、源文件由編譯器編譯成字節(jié)碼(ByteCode)

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括涿鹿網(wǎng)站建設(shè)、涿鹿網(wǎng)站制作、涿鹿網(wǎng)頁(yè)制作以及涿鹿網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,涿鹿網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到涿鹿省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!
2、字節(jié)碼由java虛擬機(jī)解釋運(yùn)行。因?yàn)閖ava程序既要編譯同時(shí)也要經(jīng)過(guò)JVM的解釋運(yùn)行,所以說(shuō)Java被稱(chēng)為半解釋語(yǔ)言( "semi-interpreted" language)。
下面通過(guò)以下這個(gè)java程序,來(lái)說(shuō)明java程序從編譯到最后運(yùn)行的整個(gè)流程。代碼如下:
//MainApp.java
public class MainApp {
public static void main(String[] args) {
Animal animal = new Animal("Puppy");
animal.printName();
}
}
//Animal.java
public class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void printName() {
System.out.println("Animal ["+name+"]");
}
}
第一步(編譯): 創(chuàng)建完源文件之后,程序會(huì)先被編譯為.class文件。Java編譯一個(gè)類(lèi)時(shí),如果這個(gè)類(lèi)所依賴(lài)的類(lèi)還沒(méi)有被編譯,編譯器就會(huì)先編譯這個(gè)被依賴(lài)的類(lèi),然后引用,否則直接引用,這個(gè)有點(diǎn)象make。如果java編譯器在指定目錄下找不到該類(lèi)所其依賴(lài)的類(lèi)的.class文件或者.java源文件的話(huà),編譯器話(huà)報(bào)“cant find symbol”的錯(cuò)誤。
編譯后的字節(jié)碼文件格式主要分為兩部分:常量池和方法字節(jié)碼。常量池記錄的是代碼出現(xiàn)過(guò)的所有token(類(lèi)名,成員變量名等等)以及符號(hào)引用(方法引用,成員變量引用等等);方法字節(jié)碼放的是類(lèi)中各個(gè)方法的字節(jié)碼。下面是MainApp.class通過(guò)反匯編的結(jié)果,我們可以清楚看到.class文件的結(jié)構(gòu):
第二步(運(yùn)行):java類(lèi)運(yùn)行的過(guò)程大概可分為兩個(gè)過(guò)程:1、類(lèi)的加載 2、類(lèi)的執(zhí)行。需要說(shuō)明的是:JVM主要在程序第一次主動(dòng)使用類(lèi)的時(shí)候,才會(huì)去加載該類(lèi)。也就是說(shuō),JVM并不是在一開(kāi)始就把一個(gè)程序就所有的類(lèi)都加載到內(nèi)存中,而是到不得不用的時(shí)候才把它加載進(jìn)來(lái),而且只加載一次。
下面是程序運(yùn)行的詳細(xì)步驟:
在編譯好java程序得到MainApp.class文件后,在命令行上敲java AppMain。系統(tǒng)就會(huì)啟動(dòng)一個(gè)jvm進(jìn)程,jvm進(jìn)程從classpath路徑中找到一個(gè)名為AppMain.class的二進(jìn)制文件,將MainApp的類(lèi)信息加載到運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),這個(gè)過(guò)程叫做MainApp類(lèi)的加載。
然后JVM找到AppMain的主函數(shù)入口,開(kāi)始執(zhí)行main函數(shù)。
main函數(shù)的第一條命令是Animal animal = new Animal("Puppy");就是讓JVM創(chuàng)建一個(gè)Animal對(duì)象,但是這時(shí)候方法區(qū)中沒(méi)有Animal類(lèi)的信息,所以JVM馬上加載Animal類(lèi),把Animal類(lèi)的類(lèi)型信息放到方法區(qū)中。
加載完Animal類(lèi)之后,Java虛擬機(jī)做的第一件事情就是在堆區(qū)中為一個(gè)新的Animal實(shí)例分配內(nèi)存, 然后調(diào)用構(gòu)造函數(shù)初始化Animal實(shí)例,這個(gè)Animal實(shí)例持有著指向方法區(qū)的Animal類(lèi)的類(lèi)型信息(其中包含有方法表,java動(dòng)態(tài)綁定的底層實(shí)現(xiàn))的引用。
當(dāng)使用animal.printName()的時(shí)候,JVM根據(jù)animal引用找到Animal對(duì)象,然后根據(jù)Animal對(duì)象持有的引用定位到方法區(qū)中Animal類(lèi)的類(lèi)型信息的方法表,獲得printName()函數(shù)的字節(jié)碼的地址。
開(kāi)始運(yùn)行printName()函數(shù)。
特別說(shuō)明:java類(lèi)中所有public和protected的實(shí)例方法都采用動(dòng)態(tài)綁定機(jī)制,所有私有方法、靜態(tài)方法、構(gòu)造器及初始化方法都是采用靜態(tài)綁定機(jī)制。而使用動(dòng)態(tài)綁定機(jī)制的時(shí)候會(huì)用到方法表,靜態(tài)綁定時(shí)并不會(huì)用到。
1、java編譯生成的字節(jié)碼,在所有操作系統(tǒng)都是一樣,故其有這樣的特點(diǎn):
write once, run anywhere.其意思:只需要一次編碼,就可以在任何環(huán)境下運(yùn)行。
2、不同的操作系統(tǒng),其java 虛擬機(jī)是不一樣的。虛擬機(jī)將java字節(jié)代碼轉(zhuǎn)換對(duì)應(yīng)操作系統(tǒng)的
相關(guān)指令,保證其正常運(yùn)行。
3、java 系統(tǒng)支持所有的硬件的平臺(tái),不存在你提及的問(wèn)題,你可以放心使用。
4、解釋器在java虛擬機(jī)中,編譯器在JDK或JRE 中。
5、java虛擬機(jī)就是常說(shuō)的java 運(yùn)行環(huán)境,其縮寫(xiě)是 JRE,安裝在操作系統(tǒng)下的一個(gè)目錄中,
這個(gè)目錄在安裝時(shí)可以由你自行指定,就像你安裝其它應(yīng)用軟件一樣。JDK中包含了JRE,
還有開(kāi)發(fā)環(huán)境,如編譯器,幫助文檔生成器,以及系統(tǒng)API的jar庫(kù)文件等。
1,如果java文件沒(méi)有package,就默認(rèn)給文件加上"無(wú)名"package;
2,默認(rèn)導(dǎo)入java.lang包,所以我們的java程序中可以使用Sting,Math,Integer等類(lèi),包括一些異常類(lèi);
3,如果生成的類(lèi)沒(méi)有父類(lèi),則為這個(gè)類(lèi)隱式加上父類(lèi):Object;因此,包括Object中的許多方法可以使用;
4,字段的初始化;
二,我們所看的到的:
既然看的到,就先看程序運(yùn)行結(jié)果:
public class JRun1 {
public JRun1() {
System.out.println(" 構(gòu)造函數(shù)");
}
static
{
System.out.println("static{}");
}
{
System.out.println("{}");
}
public static void main(String[] args) {
System.out.println("main()");
}
}
運(yùn)行結(jié)果:
static{}
main()
顯然,程序運(yùn)行時(shí),先運(yùn)行:
static
{
System.out.println("static{}");
}
再調(diào)用main();
如果我們?cè)陬?lèi)中建立一個(gè)對(duì)象:
public class JRun1 {
public JRun1() {
System.out.println(" 構(gòu)造函數(shù)");
}
static
{
System.out.println("static{}");
}
{
System.out.println("{}");
}
public static void main(String[] args) {
System.out.println("main()");
new JRun1();
}
}
運(yùn)行結(jié)果:
static{}
main()
{}
構(gòu)造函數(shù)
從而,我們得出:
建立一個(gè)非主類(lèi)對(duì)象,順序?yàn)?靜態(tài)初始化塊static{}--初始化塊{}--構(gòu)造函數(shù)constructor;
那么,牽涉到繼承,運(yùn)行流程又如何?
看程序:
class JRun1Father{
JRun1Father(){
System.out.println("父類(lèi)構(gòu)造函數(shù)");
}
static{
System.out.println("父類(lèi)靜態(tài)初始化塊");
}
{
System.out.println("父類(lèi)初始化塊");
}
}
public class JRun1 extends JRun1Father{
public JRun1() {
System.out.println("子類(lèi)構(gòu)造函數(shù)");
}
static
{
System.out.println("子類(lèi)靜態(tài)初始化塊");
}
{
System.out.println("子類(lèi)初始化塊");
}
public static void main(String[] args) {
//System.out.println("主方法)");
new JRun1();
}
}
運(yùn)行結(jié)果:
父類(lèi)靜態(tài)初始化塊
子類(lèi)靜態(tài)初始化塊
父類(lèi)初始化塊
父類(lèi)構(gòu)造函數(shù)
子類(lèi)初始化塊
子類(lèi)構(gòu)造函數(shù)
所以,牽涉到父類(lèi):父靜態(tài)--子靜態(tài)--父初始化及構(gòu)造--子初始化及構(gòu)造;
注意:初始化塊和構(gòu)造是接連運(yùn)行的,不會(huì)父類(lèi)子類(lèi)交替.
Java編譯原理:
Java 虛擬機(jī)(JVM)是可運(yùn)行Java 代碼的假想計(jì)算機(jī)。只要根據(jù)JVM規(guī)格描述將解釋器移植到特定的計(jì)算機(jī)上,就能保證經(jīng)過(guò)編譯的任何Java代碼能夠在該系統(tǒng)上運(yùn)行。
一.Java源文件的編譯、下載 、解釋和執(zhí)行
Java應(yīng)用程序的開(kāi)發(fā)周期包括編譯、下載 、解釋和執(zhí)行幾個(gè)部分。Java編譯程序?qū)ava源程序翻譯為JVM可執(zhí)行代碼?字節(jié)碼。這一編譯過(guò)程同C/C++ 的編譯有些不同。當(dāng)C編譯器編譯生成一個(gè)對(duì)象的代碼時(shí),該代碼是為在某一特定硬件平臺(tái)運(yùn)行而產(chǎn)生的。因此,在編譯過(guò)程中,編譯程序通過(guò)查表將所有對(duì)符號(hào)的引用轉(zhuǎn)換為特定的內(nèi)存偏移量,以保證程序運(yùn)行。Java編譯器卻不將對(duì)變量和方法的引用編譯為數(shù)值引用,也不確定程序執(zhí)行過(guò)程中的內(nèi)存布局,而是將這些符號(hào)引用信息保留在字節(jié)碼中,由解釋器在運(yùn)行過(guò)程中創(chuàng)立內(nèi)存布局,然后再通過(guò)查表來(lái)確定一個(gè)方法所在的地址。這樣就有效的保證了Java的可移植性和安全 性。
運(yùn)行JVM字節(jié)碼的工作是由解釋器來(lái)完成的。解釋執(zhí)行過(guò)程分三部進(jìn)行:代碼的裝入、代碼的校驗(yàn)和代碼的執(zhí)行。裝入代碼的工作由"類(lèi)裝載器"(class loader)完成。類(lèi)裝載器負(fù)責(zé)裝入運(yùn)行一個(gè)程序需要的所有代碼,這也包括程序代碼中的類(lèi)所繼承的類(lèi)和被其調(diào)用的類(lèi)。當(dāng)類(lèi)裝載器裝入一個(gè)類(lèi)時(shí),該類(lèi)被放在自己的名字空間中。除了通過(guò)符號(hào)引用自己名字空間以外的類(lèi),類(lèi)之間沒(méi)有其他辦法可以影響其他類(lèi)。在本臺(tái)計(jì)算機(jī)上的所有類(lèi)都在同一地址空間內(nèi),而所有從外部引進(jìn)的類(lèi),都有一個(gè)自己獨(dú)立的名字空間。這使得本地類(lèi)通過(guò)共享相同的名字空間獲得較高的運(yùn)行效率,同時(shí)又保證它們與從外部引進(jìn)的類(lèi)不會(huì)相互影響。當(dāng)裝入了運(yùn)行程序需要的所有類(lèi)后,解釋器便可確定整個(gè)可執(zhí)行程序的內(nèi)存布局。解釋器為符號(hào)引用同特定的地址空間建立對(duì)應(yīng)關(guān)系及查詢(xún)表。通過(guò)在這一階段確定代碼的內(nèi)存布局,Java很好地解決了由超類(lèi)改變而使子類(lèi)崩潰的問(wèn)題,同時(shí)也防止了代碼對(duì)地址的非法訪(fǎng)問(wèn)。
隨后,被裝入的代碼由字節(jié)碼校驗(yàn)器進(jìn)行檢查。校驗(yàn)器可發(fā)現(xiàn)操作數(shù)棧溢出,非法數(shù)據(jù)類(lèi)型轉(zhuǎn)化等多種錯(cuò)誤。通過(guò)校驗(yàn)后,代碼便開(kāi)始執(zhí)行了。
Java字節(jié)碼的執(zhí)行有兩種方式:
1.即時(shí)編譯方式:解釋器先將字節(jié)碼編譯成機(jī)器碼,然后再執(zhí)行該機(jī)器碼。
2.解釋執(zhí)行方式:解釋器通過(guò)每次解釋并執(zhí)行一小段代碼來(lái)完成Java字節(jié)碼程 序的所有操作。
通常采用的是第二種方法。由于JVM規(guī)格描述具有足夠的靈活性,這使得將字節(jié)碼翻譯為機(jī)器代碼的工作
具有較高的效率。對(duì)于那些對(duì)運(yùn)行速度要求較高的應(yīng)用程序,解釋器可將Java字節(jié)碼即時(shí)編譯為機(jī)器碼,從而很好地保證了Java代碼的可移植性和高性能。
樓主你好:
首先,main()方法,因?yàn)樗膶傩允莝tatic的,所以在程序最開(kāi)始運(yùn)行~~~在main方法中,通過(guò)先前寫(xiě)的一個(gè)類(lèi),生成實(shí)例對(duì)象(通過(guò)new得到),這個(gè)對(duì)象就擁有了這個(gè)類(lèi)的方法~~~~~~~~
這個(gè)對(duì)象就可以直接采用"對(duì)象.方法
()“來(lái)實(shí)現(xiàn)某種功能了~
概括地說(shuō),就是”類(lèi)擁有方法,對(duì)象是類(lèi)的一個(gè)具體的實(shí)例,他可以調(diào)用方法,方法可以用對(duì)象直接跟上方法進(jìn)行調(diào)用,從而實(shí)現(xiàn)某種功能行為“。。
當(dāng)前題目:java代碼實(shí)現(xiàn)過(guò)程 JAVA程序的開(kāi)發(fā)過(guò)程
網(wǎng)站路徑:http://chinadenli.net/article0/hjieio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開(kāi)發(fā)、網(wǎng)站排名、微信公眾號(hào)、網(wǎng)站收錄、網(wǎng)站建設(shè)、靜態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)