現(xiàn)象:我們?cè)诰幾g源文件EncodingTest.java時(shí),編譯通過(guò);但用java EncodigngTest解析EncdoingTest.class文件時(shí),總是顯示亂碼.
EncodingTest.java內(nèi)容如下:
public class EncodingTest
{
public static void main(String args[])
{
System.out.println("A中國(guó)A");
}
}
執(zhí)行javac EncodingTest后顯示如下:
理論上,應(yīng)該是輸出 “A中國(guó)A”,那為什么會(huì)出現(xiàn)亂碼呢?
我們來(lái)看看從java源文件到解析生成class文件,這一過(guò)程發(fā)生了什么事情,如下圖:
(1) 當(dāng)我們執(zhí)行javac命令時(shí),如果沒(méi)有指明encoding參數(shù),編譯器就會(huì)把源文件當(dāng)作GB2312編碼格式的文件編譯成為UTF-8編碼的class文件。
(2) 當(dāng)我們執(zhí)行java命令的時(shí)候,JVM把class文件的UTF-8字符轉(zhuǎn)化為UNICODE格式的編碼字符加載進(jìn)內(nèi)存中.
顯然,解析class文件出現(xiàn)亂碼的源頭就是在編譯的時(shí)候.把上面的EncodingTest.java用記事本打開(kāi),點(diǎn)擊“文件”>>“另存為”,可以看到下圖:
所以原因就在于:我們的源文件的編碼格式為UTF-8,編譯器默認(rèn)地把它當(dāng)作GB2312的編碼格式編譯成class文件,必然會(huì)出現(xiàn)亂碼!
我們把上面的源文件記事本打開(kāi),“文件”>“另存為”然后直接按保存(備份源文件),再執(zhí)行javac EncodingTest.java,發(fā)現(xiàn)編譯報(bào)錯(cuò),奇怪為什么同樣是一個(gè)UTF-8編碼的源文件,我們沒(méi)有作過(guò)任何修改,那為什么第一次執(zhí)行通過(guò),而第二次執(zhí)行會(huì)報(bào)錯(cuò)呢?
用16進(jìn)制編輯軟件打開(kāi),發(fā)現(xiàn)我們第二次保存的源文件多了“EF BB BF”文件頭,所以原因很明顯:
當(dāng)我們用javac編譯第一個(gè)源文件時(shí),由于沒(méi)有文件頭,所以可以把編譯器騙過(guò)去;但第二次保存的那個(gè)文件,由于多了UTF-8的文件頭,當(dāng)編譯器用默認(rèn)的GB2132來(lái)編譯源文件時(shí),發(fā)現(xiàn)文件頭是UTF-8的文件頭就認(rèn)為我們是在騙它,所以徹底讓編譯不通過(guò)!
那么是不是我們指明編譯時(shí)源文件的編碼,編譯就可以通過(guò)且正確解析呢?用第二次保存的文件,我們執(zhí)行javac –encoding UTF-8 EncodingTest.java,發(fā)現(xiàn)編譯不通過(guò);把文件頭刪去,再執(zhí)行上面命令,發(fā)現(xiàn)編碼和解析都正常進(jìn)行,由此得知編譯器只認(rèn)識(shí)沒(méi)有文件頭的UTF-8編碼格式文件!
由分析可知,如果一個(gè)java源文件通過(guò),但解析顯示出錯(cuò),那么極大可能是編譯時(shí)編碼轉(zhuǎn)化出了問(wèn)題!