1. 四个涉及编码的环节
java开发中的乱码问题,有4个环节:
1. java文件的编码。
2. class文件的编码。
3. jvm中的字符串编码。
4. 外部资源的编码。
2. java 文件的编码
java文件是可以指定编码的,默认是系统编码,如果GBK。
public static void main(String[] args) { String s = "汉"; System.out.println(s); }
文件以GBK保存。只要我们以 GBK打开文件,汉字部分就正常显示。
结论:java源文件可以任意编码
3. class 文件编码
当 java文件编译成class时候,进行了一次编码转换。这里的例子是 GBK 到UTF8
也就是说 class文件是以UTF8格式保存的。
所以以UTF8打开这个class,我们能够看到这样的字符串:
“([Ljava/lang/String;)V 汉”
当然,有些字符不能正确显示,需要以HEX查看。
结论:class文件是UTF8编码
4. jvm中的字符串编码。
jvm中的字符串是 unicode的,或者叫 UTF16。(下面证据不太直接。)
String s1 = "汉"; String s2 = "お"; System.out.println(Integer.toString(s1.charAt(0), 16)); System.out.println(Integer.toString(s2.charAt(0), 16)); System.out.println(s1+s2);
5. 外部资源的编码
主要是各种可以和外部产生联系的输入和输出。
如,System.out/err/in这些是流,外部存在的文件(读入或写出)
System.out/err/in,默认使用系统编码集。
如,export LANG=en_US.UTF8
外部文件,在read或write时,指定合适的编码即可。
6. 字符集转换
字符集的转换很多时候会丢失信息,从而产生乱码。
因此,一定要有正确的编码集使字符串变为正确的unicode。
大家经常看到这样的东西:new String(input.getBytes("ISO-8859-1"), "GBK")
发生了一下事情。
1) String(GBK) -->byte[](ISO-8859-1) -->JVM(UTF16) 这里是乱码
2) JVM(UTF16) -->byte[](ISO-8859-1) -->byte[GBK]-->JVM(UTF16) 这里转回来了。
如果是 String(GBK) -->byte[](GBK) -->JVM(UTF16), 那么就不会有乱码了。
7. 区分字符集和字体
有些时候,乱码是因为字体显示不正确造成的,这个赖不上字符集。
表象上:字体造成的乱码,一般表现为豆腐块,字符集表现为 问号。