1.编辑*.java文件时发生了什么事情呢?
答:当我们用记事本编辑时,
打开紫光输入法,紫光输入法软件控制了键盘,从键盘敲击的字母变成了拼音,拼音下方显示的是GBK中的简体还是繁体取决于指定的"简体""GBK",此时上方的"yanlei"就有了下方的汉字"眼泪"而不是"眼淚".
在空格录入"眼泪"以后,表征这两个字的键盘输入文件设备缓冲区内被存入了D1BBC0E1,这是由于紫光指定了"简体GBK"进而cpu告知系统IO设备管理器得知输入的字符是简体GBK,因此I操作接收了紫光送来的D1BBC0E1进入缓冲区.键盘文件录入设备有编码集"简体GBK"
由于并行处理的机制,完成这个输入动作后,cpu得到输入IO管理器的I输入完成中断指令,cpu利马把缓冲区的内容往内存处理区中送,这个送的过程伴随着一个码转换函数的调用,就是GBK码D1BBC0E1往Unicode内存处理码FFFE3C77EA6C的转换,当cpu把缓冲区D1BBC0E1送至处理区FFFE3C77EA6C完毕,发现O操作线程提出了需要显示的处理,紧接着又调用码转换函数Unicode内存处理码FFFE3C77EA6C往屏显缓冲区GBK码D1BBC0E1的转换动作,当转换完毕,开始调度IO设备让它进行O显示操作(这里的内存处理码的转换对用户来说是透明的,用户完全可以理解"入缓冲-处理区-出缓冲"是同一个码副本)
IO设备得到cpu通知说可以取出屏显缓冲区内容进行显示了,IO取出D1BBC0E1对照字体映射字符点阵符号表进行展示"眼泪",取出D1BBC0E1这些01代码时到底按照哪个编码进行展示呢?这时屏显文件输出设备利用了系统Locale代码页也就是ANSI936 GBK代码页就行展示,根据不同的字体显示同一个中文字符的不同字符点阵符号。所以这里屏显设备也参考了编码集才能进行正确显示
键盘入缓冲GBK->内存处理unicode->屏显出缓冲GBK的一个转换(文件保存缓冲采用GBK码的一个副本), 是透明的
2.编辑好的*.java文件保存时发生了哪些事情呢?
答:编辑好的java源文件可以采用默认的GBK即ANSI936来保存文件,至于各种保存方案为什么存在以及各自的优缺点在上方的【源文件文件保存:】这里有介绍。所以在此处我们也就理解了eclipse工作空间workspace设定编码方案类似于另存为弹出窗口编码下拉框的指定
键盘入缓冲GBK->内存处理unicode->文件保存缓冲GBK的一个转换,是透明的
文件保存缓冲UTF-8的一个转换,是透明的
文件保存缓冲unicode的一个转换,是透明的
3.编译java源文件的时候发生了什么呢?
答:javac命令 javac -file.encoding xxx.java通过这个指令我们知道-file.encoding这个属性是有作用的
-file.encoding告诉JVM虚拟机是用什么编码方式保存文件的,
pageEncoding
setContentType()
setCharacterEncoding()
3.1 当我们保存java源程序文件为GBK即ANSI代码页时,取出编译时javac默认-file.encoding取的当前系统的默认文件编码方案,所以取出文件缓冲池内的"眼泪"D1BBC0E1会被正确的转换到内存处理区FFFE3C77EA6C,处理完了之后待生成*.class文件保存的时候又把内存处理区FFFE3C77EA6C转换成了UTF-8格式EFBBBFE79CBCE6B3AA保存在了*.class文件之中,因为*.class文件默认使用UTF-8保存。
动作:[GBK录入->unicode->GBK码文件缓冲(编辑时入)]====源文件怎么保存来的
|||||||||||||||||||||||
GBK码文件缓冲(编译时出)->unicode->UTF-8码class文件保存
可以看出取出文件时,文件编码被对待成保存成的编码是正确的
3.2 当我们保存java源程序文件为UTF-8时(动作:GBK码D1BBC0E1->处理区FFFE3C77EA6C->UTF-8码EFBBBFE79CBCE6B3AA),取出编译时javac默认-file.encoding取的当前系统的默认文件编码GBK方案系统Locale语言指定,所以此处我们就需要进行源文件编码的指定.
3.2.1 如果我们没有重新指定的话:UTF-8格式EFBBBFE79CBCE6B3AA文件读出流的"眼泪"就会被当作是GBK编码E79C,BCE6,B3AA,造成错误,进行了GBK文件读出流->unicode处理->UTF-8码class文件保存的过程,在这个过程中GBK文件读出流发生了错误,导致以后的整个过程的错误.
动作:[GBK录入->unicode->utf-8码文件缓冲(编辑时入)]====源文件怎么保存来的
|||||||||||||||||||||||
GBK码文件缓冲(编译时出)->unicode->UTF-8码class文件保存
可以看出取出文件时,文件编码被对待成GBK编码是错误的
3.2.2 如果我们指定了-file.encoding=utf-8,这时编译器就会知道源码是utf-8编码.
动作:[GBK录入->unicode->utf-8码文件缓冲(编辑时入)]====源文件怎么保存来的
|||||||||||||||||||||||
utf-8码文件缓冲(编译时出)->unicode->UTF-8码class文件保存
可以看出取出文件时,文件编码被对待成保存时的utf-8编码是正确的
4.执行.class文件的时候发生了什么呢?
当JVM执行.class文件时,jvm直接将保存的utf-8格式的class文件拿出来执行,进行
utf-8码class文件->内存处理unicode->处理后屏显GBK码,追加以前的从编辑开始的动作,如下:
[GBK录入->unicode->utf-8码文件缓冲(编辑时入)]====java源文件怎么保存的
|||||||||||||||||||||||
utf-8码文件缓冲(编译时出)->unicode->UTF-8码class类文件怎么编译保存的
||||||||||||||||
UTF-8码class文件->unicode->GBK码屏显 class类文件怎么执行
好:通过以上三个环节之后,我们就知道jvm虚拟机处理编码工作的原理,
在这里需要强调一下,
unicode->UTF-8码class类文件怎么编译保存的
||||||||||||||||
UTF-8码class文件读出->unicode
这个类文件的细节编码是我们不需要关心的,因为类文件的编码解码都是由JVM自动实现的,不需要本地操作系统file.encoding属性的参与的,对用户来说是透明的,所以我们可以不必考虑这层码的转换.
那么:上诉动作可以简化为:
GBK录入->unicode->utf-8码文件缓冲(编辑时入)]====java源文件怎么保存的
|||||||||||||||||||||||
utf-8码文件缓冲(编译时出)->unicode->->GBK屏显 class类文件怎么执行
其中GBK录入和GBK屏显都是根据系统Locale ANSI936来决定的
简化了之后我们可以看出文件的保存时编码和取出时编码是至关重要的,这里如果发生了错误,尤其是取出时编码的误认为-file.encoding=系统Locale是致命的。
针对普通Java类:
一句话总结:针对静态字符串文件以什么码保存就必需以什么码取出编译javac -file.encoding="文件保存码"
针对动态字符串,如从数据库数据文件存取内容时,数据文件什么码,rs.getString().getBytes("数据文件编码") 取出时new String(rs.getString().getBytes("数据文件编码"),"java文件保存码")
存入时new String(str.getBytes("java文件保存码"),"数据文件编码");
这里所设计都是普通的java类,那么jsp和servlet又是怎样的呢