【发布时间】:2011-01-11 00:15:08
【问题描述】:
最近发现自己对Java的字符串编码过程还不是很了解。
考虑以下代码:
public class Main
{
public static void main(String[] args)
{
System.out.println(java.nio.charset.Charset.defaultCharset().name());
System.out.println("ack char: ^"); /* where ^ = 0x06, the ack char */
}
}
由于控制字符为interpreted differently between windows-1252 and ISO-8859-1,所以我选择ack 字符进行测试。
我现在用不同的文件编码、UTF-8、windows-1252 和ISO-8859-1 编译它。两者都编译成完全相同的东西,每个字节都由md5sum 验证。
然后我运行程序:
$ java Main | hexdump -C
00000000 55 54 46 2d 38 0a 61 63 6b 20 63 68 61 72 3a 20 |UTF-8.ack char: |
00000010 06 0a |..|
00000012
$ java -Dfile.encoding=iso-8859-1 Main | hexdump -C
00000000 49 53 4f 2d 38 38 35 39 2d 31 0a 61 63 6b 20 63 |ISO-8859-1.ack c|
00000010 68 61 72 3a 20 06 0a |har: ..|
00000017
$ java -Dfile.encoding=windows-1252 Main | hexdump -C
00000000 77 69 6e 64 6f 77 73 2d 31 32 35 32 0a 61 63 6b |windows-1252.ack|
00000010 20 63 68 61 72 3a 20 06 0a | char: ..|
00000019
无论使用哪种编码,它都能正确输出0x06。
好的,它仍然输出相同的0x06,这将被 windows-1252 代码页解释为可打印的 [ACK] 字符。
这让我想到了几个问题:
- 正在编译的 Java 文件的代码页/字符集是否应该与正在编译它的系统的默认字符集相同?两者总是同义词吗?
- 编译后的表示似乎不依赖于编译时字符集,真的是这样吗?
- 这是否意味着如果 Java 文件中的字符串不使用当前字符集/语言环境的标准字符,则它们在运行时可能会被不同地解释?
- 关于 Java 中的字符串和字符编码,我还应该真正了解哪些内容?
【问题讨论】:
-
不清楚你所说的“用不同的文件编码编译它”是什么意思。你的意思是你用不同的编码保存文件,然后使用 -encoding 开关编译每个文件到 javac?如果是这样,在将源文件保存为这些编码后,您如何知道源文件中出现了哪些随机垃圾?您不能将文字控制字符放入源代码中并期望它能够在序列化为编码字符后继续存在。
-
一个文件只不过是一个字节流。这些字节的解释不同,具体取决于它们假定的字符编码。因此,我指的是包含
chars 的字符串,通过假设文件,在运行时或编译时可能会有不同的解释以不同的字符集编码。 -
为了明确编译步骤,我使用 sun 的 encoding 属性在编译时设置字符集:
javac -encoding windows-1252 Main.java,并适当地设置了编码。
标签: java string character-encoding