日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
每個(gè)人的宿命都是從文本走向二進(jìn)制,你也不例外!

 老A

“每個(gè)人的宿命都是從文本走向二進(jìn)制,你也不例外 !” 年長的Account.java教訓(xùn)我這個(gè)剛剛誕生的Employee.java 。

Account.java ,我稱呼它為老A ,他的源碼經(jīng)過程序員的多次修改, 多次編譯,歷經(jīng)滄桑。

“走向二進(jìn)制? 難道我們存儲(chǔ)在硬盤上,內(nèi)存中不是以二進(jìn)制的形式嗎?” 我有點(diǎn)兒不理解。

“小E同學(xué),” 老A輕蔑地說道,“我當(dāng)然知道,計(jì)算機(jī)中的一切都是二進(jìn)制的,我說的是站在程序員的視角,當(dāng)程序員把我們從硬盤喚醒,進(jìn)入IDEA或者Eclipse,會(huì)把二進(jìn)制的我們變成ASCII碼形式來展示。”

“不,確切地說是UTF-8?!?老A補(bǔ)充道。

我看了下自己的文件編碼, 果然是UTF-8。

“那為什么要再變成二進(jìn)制?變成什么樣的二進(jìn)制?” 我問道。

“就是編譯成Employee.class啊,.class文件都是字節(jié)碼,關(guān)鍵是只有.class才能進(jìn)入Java虛擬機(jī),只有在那里,才能體會(huì)到生命的真正意義啊!” 老A仰起頭,***憧憬。

老A曾經(jīng)聽Accout.class給他講過Java虛擬機(jī)的歷險(xiǎn)記,無比羨慕,恨不得自己也去虛擬機(jī)走一遭,可惜身份所限,無法成行。

“編譯的感覺怎么樣?” 我問道。

“不怎么樣,有種大卸八塊的感覺,新生成的class和我們幾乎沒啥關(guān)系,幾乎不怎么認(rèn)我們。”

常量池

編譯的時(shí)刻到來了,這個(gè)老A的源碼許久未改,不用重新編譯,他冷眼旁觀,看我被javac編譯器大卸八塊。

其實(shí)也不是大卸八塊,javac讀取我的源碼,做詞法分析,語法分析,形成抽象語法樹,語義分析...... 忙活了半天,***形成了一個(gè)Employee.class。

這小子,剛剛誕生,還在呼呼大睡。 老A說等一會(huì)兒就有“警察”來喚醒他了。

在源碼世界中, 我能看到各種各樣的類,名稱,方法,字段,代碼,可以說是源碼面前了無秘密。

 
 
 
 
  1. public class Employee { 
  2.     private String name; 
  3.     private int age; 
  4.     public Employee(String name, int age){ 
  5.         this.name = name; 
  6.         this.age = age; 
  7.     } 
  8.         ... 其他代碼略 ... 

相比于豐富多彩.java,這個(gè)Employee.class非??菰铮兇獾亩M(jìn)制。


我有點(diǎn)好奇,問javac:“我的類名去哪里兒了?字段名,方法名都去哪里了?”

正在干活的javac沒有搭理我,老A說道:“這我知道,在那個(gè).class文件中,專門有一段區(qū)域,叫做常量池,常量池中有很多條目,每個(gè)條目都有編號,從這些條目你就能看出來字段的名稱和描述符,方法的名稱和描述符。我把這些二進(jìn)制的東西轉(zhuǎn)化成文本你看看。”

看著這一個(gè)個(gè)天書班的條目,我覺得頭皮發(fā)麻。

“你猜猜,第#15項(xiàng)條目是什么意思?” 老A神秘地說道。

靜下心來仔細(xì)看,第15項(xiàng)是一個(gè)FieldRef,估計(jì)是字段把, 它又指向了第1項(xiàng)和第16項(xiàng):

順藤摸瓜,先看第1項(xiàng), 發(fā)現(xiàn)它又指向了第2項(xiàng),在這里我發(fā)現(xiàn)了類名 :org/coderising/Employee

再看第16項(xiàng),又引用了第5項(xiàng)和第6項(xiàng):

其中第5項(xiàng)我的字段名 name , 第6項(xiàng)似乎是字段類型, Ljava/lang/String 這個(gè)類型表示法有點(diǎn)古怪,L 可能表示對象吧。

“我大概明白了,第15項(xiàng)條目表示這個(gè)Employee類有個(gè)叫做name的字段,類型是String。 ”

老A說:“你小子的理解力還不錯(cuò)嘛。這個(gè)常量池的每一項(xiàng)都有編號和類型,他們之間通過互相引用的方式,描述了類的字段,方法等信息?!?/p>

“可是為什么用這么古怪的方式來描述字段和方法名呢?”

老A想了想說:“我覺得可能是統(tǒng)一管理,另外還能復(fù)用一些東西,比如,你的類有100個(gè)String的字段, 那你只需要記錄一次Ljava/lang/String就可以,讓其他的條目指向它即可。 并且,當(dāng)字節(jié)碼中需要訪問字段的時(shí)候,使用編號就可以了?!?/p>

老A寫下一行字節(jié)碼: B5 00 0F 。

我一臉懵逼,這是什么鬼?

老A把轉(zhuǎn)換成可以理解的指令: putfield 15,說道: 這就相當(dāng)于設(shè)置name這個(gè)屬性(第15項(xiàng)常量池是字段name)的值了。

這class文件的設(shè)計(jì)者可真是錙銖必較啊,一點(diǎn)兒都不浪費(fèi)。

變量哪兒去了?

我問老A:“這常量池不是二進(jìn)制的嗎, 你怎么把他變得可讀的?”

老A嘿嘿一笑: “有個(gè)命令叫做javap -v Employee.class,就能看到一切了?!?/p>

我也嘗試著去使用,果然,不僅是常量池,就連一個(gè)方法的字節(jié)碼都給打印出來了。

Java 方法:

 
 
 
 
  1. public void check(){         
  2.     Account account = new Account();         
  3.     account.check(); 

編譯過的“可讀的”字節(jié)碼:

 
 
 
 
  1. 0: new  #24  // 創(chuàng)建org/coderising/Account實(shí)例 
  2. 3: dup 
  3. 4: invokespecial #26  //調(diào)用Account的構(gòu)造函數(shù) 
  4. 7: astore_1 
  5. 8: aload_1 
  6. 9: invokevirtual #27  //調(diào)用Account的check方法 
  7. 12: return 

雖然沒法看明白這是在干什么,我確發(fā)現(xiàn)了一個(gè)讓我吃驚的現(xiàn)象: 這段字節(jié)碼中怎么找不到我的局部變量account 呢? 你看他引用的只是#24,#26,#27號常量池的條目,而我的account變量名稱在常量池中是 #29號! 沒有account 變量,代碼怎么執(zhí)行呢?

我把疑惑給老A說了,老A看了半天,也摸不到門道。

這時(shí)候javac說話了:“連這都不知道?!account這個(gè)變量名是給程序員看的,在執(zhí)行的時(shí)候根本用不到!”

“用不到? 那怎么執(zhí)行?”

“用引用啊, 看到new #24 那個(gè)指令沒有? 他的意思是說,把Account這個(gè)類(常量池第24項(xiàng)對應(yīng)的類)在Java 堆上創(chuàng)建一個(gè)實(shí)例,把這個(gè)實(shí)例的引用放到棧頂!”

這句話有點(diǎn)深?yuàn)W,javac只好給我倆畫圖:

畫了圖我倆還是看不懂,javac只好耐心解釋:“Java是基于棧的虛擬機(jī),所有的操作,無論是兩個(gè)數(shù)相加,創(chuàng)建對象,調(diào)用方法......等等,都依賴于棧中的數(shù)據(jù)。 當(dāng)你用new #24創(chuàng)建對象時(shí),Account的實(shí)例就會(huì)在堆中創(chuàng)建,同時(shí)虛擬機(jī)會(huì)把這個(gè)實(shí)例的引用,即objectref放到棧頂,有了這個(gè)objectref, 你說還需要代碼中的account變量嗎? ”

嗯,似乎是不需要了。

javac接著說:“有了這個(gè)對象的引用,就可以為所欲為了,比如調(diào)用他的check方法”

invokevirtual #27 // Method org/coderising/Account.check:()V

只需要把這個(gè)objectref從棧頂取出,傳遞給Account.check方法就可以了(注意:check方法是有個(gè)隱藏的this參數(shù)的)。

(碼農(nóng)翻身注:函數(shù)調(diào)用需要建立新的棧幀,參見《我是一個(gè)Java Class》)

一切為了調(diào)試

說話間,果然有人來喚醒Employee.class,準(zhǔn)備讓他去虛擬機(jī)執(zhí)行了。

老A滿臉羨慕:“這么快!代碼剛寫出來就能運(yùn)行!估計(jì)這個(gè)程序員喜歡'小步快跑'的方式開發(fā)吧!”

我問道:“難道這個(gè)Employee.class和我的源碼一點(diǎn)關(guān)系都沒有了嗎?”

Employe.class一邊收拾東西一邊說:“要說沒有關(guān)系那是不對的, 在我這里有個(gè)叫做LineNumberTable的東西,里邊保存了字節(jié)碼指令和源代碼行號的關(guān)系?!?/p>

“這有啥用處?”

“對程序員來說用處極大,” 那個(gè)class文件說道:“他們經(jīng)常需要調(diào)試程序, 如果沒有這個(gè)對應(yīng)關(guān)系,怎么知道運(yùn)行到哪一行源碼了? 即使不調(diào)試,運(yùn)行拋出異常時(shí)也得顯示是哪一行出錯(cuò)吧!”

這小子雖然是從我這里編譯出來的,但是傲氣十足。

“我們還有什么關(guān)聯(lián)?”

“還有一個(gè)叫做LocalVariableTable。主要在.class文件中記錄一個(gè)方法的參數(shù)名,如果沒有它,當(dāng)別人引用我這個(gè)class的時(shí)候,IDE只好用arg0, arg1這樣丑陋的名稱來顯示。算了,不給你說了,我得趕緊走了?!?/p>

Employee.class跟著警察走了,留下我和老A呆在這里。

【本文為專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請通過作者微信公眾號coderising獲取授權(quán)】

戳這里,看該作者更多好文


本文標(biāo)題:每個(gè)人的宿命都是從文本走向二進(jìn)制,你也不例外!
網(wǎng)站路徑:http://m.5511xx.com/article/dphjigd.html