引用网上一张截图,由于网上链接太多,也找不到作者,忘见谅。 一直困惑字符编码里的问题,开门见山,问题: 假设A.java文本文件采用GBK编码,那么javac编译该文件的时候,首先读取该文件,读取后编译成UTF-8编码的字节码文件,这个过程中会导致乱码,这个乱码是不可恢复的,那么为什么在最后输出的时候指定了以GBk解码,最终不会乱码。
作者:RednaxelaFX 链接:http://www.zhihu.com/question/30977092/answer/50266867 来源:知乎 著作权归作者所有,转载请联系作者获得授权。
题主贴的图完全符合实际情况。它已经很形象的说明了每个步骤会涉及的转码动作。 首先,Java源码文件。这些文件可以是任意字符编码的。 然后在Java的Class文件里存储的字符串是UTF-8编码的。 (具体是一种modified UTF-8,请参考JVM规范: Chapter 4. The class File Format String content is encoded in modified UTF-8. Modified UTF-8 strings are encoded so that code point sequences that contain only non-null ASCII characters can be represented using only 1 byte per code point, but all code points in the Unicode codespace can be represented. Modified UTF-8 strings are not null-terminated. The encoding is as follows: …… ) 从Java源码文件到Java Class文件,中间会经过Java源码编译器(例如javac或ECJ)的编译。 也就是说,是Java源码编译器负责将Java源码文件的编码转换为最终的UTF-8。 导致乱码的不是Java源码编译器的“编码”(写出UTF-8)的过程,而是“解码”(读入Java源码内容)的过程。 以javac为例,它有一个参数可以指定输入的Java源码文件的编码: -encoding encodingSet the source file encoding name, such as EUC-JP and UTF-8. If -encoding is not specified, the platform default converter is used. 关键在于“如果不指定encoding,则使用平台默认的转换器”。 在简体中文的Windows上,平台默认编码会是GBK,那么javac就会默认假定输入的Java源码文件是以GBK编码的。javac能够正确读取文件内容并将其中的字符串以UTF-8输出到Class文件里,就跟自己写个程序以GBK读文件以UTF-8写文件一样。 如果实际输入的确实是GBK编码(GBK兼容ASCII编码)的文件,那么一切都会正常。 但如果实际输入的是别的编码的文件,例如超过了ASCII范围的UTF-8,那javac读进来的内容就会出问题,就“乱码”了。 所以,在题主引用的图里,从橙色的源码文件到蓝色的编译器之间的箭头上,“桥梁”就是这个-encoding参数。