每天進步一點點持寄!
上一篇已經(jīng)學習了加載階段,這一篇我們了解一下驗證的過程娱俺。
我們已經(jīng)知道了稍味,虛擬機加載的是Class字節(jié)碼文件,我們也通過工具查看了文件中存儲的是二進制流荠卷。
下面我們打開一個文件AppTest.class模庐,我們在文件的開頭隨便加入一個字母“f”,如下圖所示油宜。
那么掂碱,我們通過命令行輸入命令“java AppTest”,會出現(xiàn)什么結果呢慎冤?
虛擬機會報一個Class文件格式化錯誤疼燥,這是我們隨便修改的一個,但是如果某些別有用心的人蚁堤,惡意修改了class文件醉者,為了避免對虛擬機造成傷害,虛擬機必須要在確保Class文件的內(nèi)容符合虛擬機的要求規(guī)范披诗。
驗證部分主要包含下面四個階段的驗證:
1. 文件格式的驗證:驗證文件格式是否按照虛擬機的規(guī)范撬即,也就是我們前面class文件結構中的內(nèi)容,比如這是不是一個Class文件(看魔數(shù)呈队,是否位CAFEBABE)剥槐;Java版本是否符合當前虛擬機的范圍(Java可以向下兼容,但是不能處理大于當前版本的程序)等等宪摧。
2. 元數(shù)據(jù)的驗證:對Class文件中的元數(shù)據(jù)進行驗證粒竖,是否存在不符合Java語義的元數(shù)據(jù)信息。
這里有的朋友可能會比較疑惑几于,什么是元數(shù)據(jù)呢蕊苗?一般情況下,一個文件中都數(shù)據(jù)和元數(shù)據(jù)孩革。數(shù)據(jù)指的是實際數(shù)據(jù)岁歉,而元數(shù)據(jù)(Metadata)是用來描述數(shù)據(jù)的數(shù)據(jù)得运。用過Java注解的朋友應該對元數(shù)據(jù)這種叫法并不陌生膝蜈,對應的元注解锅移,其實說的差不多都是一個意思。
舉個例子:比如說我們定義了一個變量 int a = 1饱搏;可以理解成數(shù)據(jù)就是1非剃,而元數(shù)據(jù)就是描述有一個字符串變量“a”,這個“a”的類型是int型的推沸,它的值也是一個int型的1备绽,這就是描述數(shù)據(jù)的數(shù)據(jù),就是元數(shù)據(jù)鬓催。
3. 字節(jié)碼的驗證:通過數(shù)據(jù)流和控制流分析肺素,來確定程序語義是否合法。
以數(shù)據(jù)來說宇驾,要保證類型轉(zhuǎn)換是有效的倍靡;對于控制流程的代碼,不能讓指令跳轉(zhuǎn)到其它方法的字節(jié)碼指令上等……
4. 符號引用的驗證:為了保證解析動作能正常完成课舍,還需在虛擬機將符號引用轉(zhuǎn)成直接引用的時候塌西,判斷其它要引用的類是否符合規(guī)定。比如筝尾,要引用的類是否能夠被找到捡需;引用的屬性在對應類中是否存在鲸伴,權限是否符合要求(private的是不能訪問的)等战得。
最后再說一點,驗證階段不是必須的兑巾,如果代碼運行已經(jīng)穩(wěn)定了之后贸街,可以通過設置參數(shù)-Xverfy:none參數(shù)來關閉類驗證庵寞,減少虛擬機的類加載時間,提高運行效率薛匪。
既然說到了驗證捐川,不知道朋友們有沒有想到另一個問題,那就是混淆逸尖。
有很多時候古沥,為了使我們的代碼不被反編譯出來,我們會對程序的關鍵部分進行加密處理娇跟,讓文件不容易被反編譯出來岩齿,混淆技術應用而生。
這里就簡單的給朋友們介紹一個工具——ProGuard苞俘,想要使用的朋友可以自行搜索查看盹沈,這里需要注意的是,混淆工具并不是百分百好用吃谣,有些涉及到反射的類是不能使用混淆工具的乞封,否則會出現(xiàn)問題做裙。
喜歡文章或想一起學習的朋友可以關注我,給我點贊肃晚,我將會持續(xù)更新锚贱,有什么疑問或文中有不當之處請給我留言,真誠地希望能與大家一起交流探討关串,學習進步拧廊。