摘要:前面三篇博客側(cè)重介紹字符但骨、編碼問(wèn)題卸勺,通過(guò)這三篇博客各位博友對(duì)各種字符編碼有了一個(gè)初步的了解,要了解java的中文問(wèn)題這是必須要了解的瞎暑。但是了解這些僅僅只是一個(gè)開始彤敛,以下博客將側(cè)重介紹java亂碼是如何產(chǎn)生的、存在哪些亂碼的情況了赌、該如何從根本上解決亂碼問(wèn)題墨榄。
java編碼轉(zhuǎn)換過(guò)程
我們總是用一個(gè)java類文件和用戶進(jìn)行最直接的交互(輸入、輸出)揍拆,這些交互內(nèi)容包含的文字可能會(huì)包含中文渠概。無(wú)論這些java類是與數(shù)據(jù)庫(kù)交互茶凳,還是與前端頁(yè)面交互嫂拴,他們的生命周期總是這樣的:
1、程序員在操作系統(tǒng)上通過(guò)編輯器編寫程序代碼并且以.java的格式保存操作系統(tǒng)中贮喧,這些文件我們稱之為源文件筒狠。
2、通過(guò)JDK中的javac.exe編譯這些源文件形成.class類箱沦。
3辩恼、直接運(yùn)行這些類或者部署在WEB容器中運(yùn)行,得到輸出結(jié)果谓形。
這些過(guò)程是從宏觀上面來(lái)觀察的灶伊,了解這個(gè)肯定是不行的,我們需要真正來(lái)了解java是如何來(lái)編碼和被解碼的:
第一步:當(dāng)我們用編輯器編寫java源文件寒跳,程序文件在保存時(shí)會(huì)采用操作系統(tǒng)默認(rèn)的編碼格式(一般我們中文的操作系統(tǒng)采用的是GBK編碼格式)形成一個(gè).java文件聘萨。java源文件是采用操作系統(tǒng)默認(rèn)支持的file.encoding編碼格式保存的。下面代碼可以查看系統(tǒng)的file.encoding參數(shù)值童太。
System.out.println(System.getProperty("file.encoding"));
第二步:當(dāng)我們使用javac.exe編譯我們的java文件時(shí)米辐,JDK首先會(huì)確認(rèn)它的編譯參數(shù)encoding來(lái)確定源代碼字符集,如果我們不指定該編譯參數(shù)书释,JDK首先會(huì)獲取操作系統(tǒng)默認(rèn)的file.encoding參數(shù)翘贮,然后JDK就會(huì)把我們編寫的java源程序從file.encoding編碼格式轉(zhuǎn)化為JAVA內(nèi)部默認(rèn)的UNICODE格式放入內(nèi)存中。
第三步:JDK將上面編譯好的且保存在內(nèi)存中信息寫入class文件中爆惧,形成.class文件狸页。此時(shí).class文件是Unicode編碼的,也就是說(shuō)我們常見(jiàn)的.class文件中的內(nèi)容無(wú)論是中文字符還是英文字符扯再,他們都已經(jīng)轉(zhuǎn)換為Unicode編碼格式了肴捉。
在這一步中對(duì)對(duì)JSP源文件的處理方式有點(diǎn)兒不同:WEB容器調(diào)用JSP編譯器,JSP編譯器首先會(huì)查看JSP文件是否設(shè)置了文件編碼格式叔收,如果沒(méi)有設(shè)置則JSP編譯器會(huì)調(diào)用調(diào)用JDK采用默認(rèn)的編碼方式將JSP文件轉(zhuǎn)化為臨時(shí)的servlet類齿穗,然后再編譯為.class文件并保持到臨時(shí)文件夾中。
第四步:運(yùn)行編譯的類:在這里會(huì)存在一下幾種情況
1饺律、直接在console上運(yùn)行窃页。
2、JSP/Servlet類。
3脖卖、java類與數(shù)據(jù)庫(kù)之間乒省。
這三種情況每種情況的方式都會(huì)不同,
1.Console上運(yùn)行的類
這種情況下畦木,JVM首先會(huì)把保存在操作系統(tǒng)中的class文件讀入到內(nèi)存中袖扛,這個(gè)時(shí)候內(nèi)存中class文件編碼格式為Unicode,然后JVM運(yùn)行它十籍。如果需要用戶輸入信息蛆封,則會(huì)采用file.encoding編碼格式對(duì)用戶輸入的信息進(jìn)行編碼同時(shí)轉(zhuǎn)換為Unicode編碼格式保存到內(nèi)存中。程序運(yùn)行后勾栗,將產(chǎn)生的結(jié)果再轉(zhuǎn)化為file.encoding格式返回給操作系統(tǒng)并輸出到界面去惨篱。整個(gè)流程如下: