我最近意识到我没有完全理解Java的字符串编码过程。从编译到运行时,Java String编码如何真正起作用
考虑下面的代码:
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?如果是这样,你怎么知道在将这些随机垃圾保存在这些编码中之后,什么随机垃圾正在清空?你不能将一个文字控制字符放入你的源代码中,并期望它能够在序列化到编码字符之后继续存在。 – 2010-01-29 20:14:56
文件不过是一个字节流。这些字节根据它们被假定为的字符编码而被不同地解释。因此,我指的是包含'char'的字符串,这些字符可以在运行时或在编译时以不同的方式解释,假设文件被编码在不同的字符集中。 – 2010-01-29 20:20:26
为了明确编译步骤,我使用了sun的编码属性在编译时设置字符集:'javac -encoding windows-1252 Main.java',编码设置得当。 – 2010-01-29 21:07:10