上一篇:
【Java 基础专题】编码与乱码(02)---String的getBytes([encoding])方法测试
【1】在中文平台下,测试的结果如下:
System default encoding --- GBK System default language --- zh
Get characters with default encoding
char[0]='中' byte=45 \u2D short=20013 \u4E2D CJK_UNIFIED_IDEOGRAPHS char[1]='文' byte=-121 \uFFFFFF87 short=25991 \u6587 CJK_UNIFIED_IDEOGRAPHS
Characters length: 2
Get characters with given encoding : ISO-8859-1
char[0]='?' byte=-42 \uFFFFFFD6 short=214 \uD6 LATIN_1_SUPPLEMENT char[1]='?' byte=-48 \uFFFFFFD0 short=208 \uD0 LATIN_1_SUPPLEMENT char[2]='?' byte=-50 \uFFFFFFCE short=206 \uCE LATIN_1_SUPPLEMENT char[3]='?' byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENT
Characters length: 4
Get characters with given encoding : GBK
char[0]='中' byte=45 \u2D short=20013 \u4E2D CJK_UNIFIED_IDEOGRAPHS char[1]='文' byte=-121 \uFFFFFF87 short=25991 \u6587 CJK_UNIFIED_IDEOGRAPHS
Characters length: 2
Get characters with given encoding : UTF-8
char[0]='?' byte=-3 \uFFFFFFFD short=-3 \uFFFFFFFD SPECIALS char[1]='?' byte=-3 \uFFFFFFFD short=-3 \uFFFFFFFD SPECIALS char[2]='?' byte=-3 \uFFFFFFFD short=-3 \uFFFFFFFD SPECIALS char[3]='?' byte=-3 \uFFFFFFFD short=-3 \uFFFFFFFD SPECIALS
Characters length: 4
|
【2】在英文平台下,测试的结果如下:
System default encoding --- Cp1252 System default language --- en
Get characters with default encoding
char[0]='?' byte=45 \u2D short=20013 \u4E2D CJK_UNIFIED_IDEOGRAPHS char[1]='?' byte=-121 \uFFFFFF87 short=25991 \u6587 CJK_UNIFIED_IDEOGRAPHS
Characters length: 2
Get characters with given encoding : ISO-8859-1
char[0]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN char[1]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
Characters length: 2
Get characters with given encoding : GBK
char[0]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN char[1]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
Characters length: 2
Get characters with given encoding : UTF-8
char[0]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN char[1]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
Characters length: 2
|
【结论】和getBytes(ncoding)不同,toCharArray()返回的是"自然字符"。但是这个"自然字符"的数目和内容却是由原始的编码方式决定的。来看看里面是如何进行字符串的操作的:
- String encodedString = new String(content.getBytes(), encoding);
- char[] charArray = inStr.toCharArray();
复制代码
可以看到系统首先对原始字符串按照默认的编码方式进行编码,得到一个字节数组,然后按照指定的新的编码方式进行解码,得到新的编码后的字符串。再转换成对应的字符数组。
由于在中文平台下,默认的字符集编码是GBK,于是content.getBytes()得到的是什么呢?就是下面这4个字节:
- byte[0] = -42 hex string = ffffffd6
- byte[1] = -48 hex string = ffffffd0
- byte[2] = -50 hex string = ffffffce
- byte[3] = -60 hex string = ffffffc4
复制代码
如果新的encoding是GBK,那么经过解码后,由于一个字符用2个字节表示。于是最终的结果就是:
- char[0]='中' --- byte[0] + byte[1]
- char[1]='文' --- byte[2] + byte[3]
复制代码
如果新的encoding是ISO-8859-1,那么经过解码后,由于一个字符用1个字节表示,于是原来本应该2个字节一起解析的变成单个字节解析,每个字节都代表了一个汉字字符的一半。这一半的字节在ISO-8859-1中找不到对应的字符,就变成了"?"了,最终的结果:
- char[0]='?' ---- byte[0]
- char[1]='?' ---- byte[1]
- char[2]='?' ---- byte[2]
- char[3]='?' ---- byte[3]
复制代码
如果新的encoding是UTF-8,那么经过解码后,由于一个字符用3个字节表示,于是原来4个字节的数据无法正常的解析成UTF-8的数据,最终的结果也是每一个都变成"?"。
- char[0]='?' ---- byte[0]
- char[1]='?' ---- byte[1]
- char[2]='?' ---- byte[2]
- char[3]='?' ---- byte[3]
复制代码
如果是在英文平台下,由于默认的编码方式是Cp1252,于是content.getBytes()得到的字节都是被截去一半的残留字符,所以我们看到在英文平台下,不论指定的encoding是GBK、UTF-8,其结果和ISO-8859-1都是一样的。
记住:这个方法再次证明了String的getBytes()方法的危险性,如果我们使用new String(str.getBytes(), encoding)对字符串进行重新编码解码时,我们一定要清楚str.getBytes()方法返回的字节数组的长度、内容到底是什么,因为在接下来使用新的encoding进行编码解码时,Java并不会自动地对字节数组进行扩展以适应新的encoding。而是按照新的编码方法直接对该字节数组进行解析。于是结果就像上面的例子一样,同样是4个原始字节,有些每2个一组进行解析,有些每个一组进行解析,有些每3个一组进行解析。其结果就只能看那种编码方式合适了。(文/
Paul Lin)
下一篇:
【Java 基础专题】编码与乱码(04)---输出时的编码与乱码