2011-01-20 125 views
6

嘿,我只是刚开始尝试学习Java,并遇到了一些令人困惑的事情!Java Unicode混淆

我从我正在使用的书中输入一个示例。它将演示 char数据类型。

的代码如下:

public class CharDemo 
{ 
public static void main(String [] args) 
{ 
char a = 'A'; 
char b = (char) (a + 1); 
System.out.println(a + b); 
System.out.println("a + b is " + a + b); 
int x = 75; 
char y = (char) x; 
char half = '\u00AB'; 
System.out.println("y is " + y + " and half is " + half); 
} 
} 

是困惑我的是位的声明,焦炭半= '\ u00AB'。该书指出\ u00AB是符号'1/2'的代码。如上所述,当我从cmd编译并运行该程序时,该行上生成的符号实际上是'1/2'。

因此,一切看起来都是应该的。我决定玩弄代码并尝试一些不同的unicode。我搜索了多个unicode表,发现它们都不符合上述结果。

在每一个我发现它说,该代码/ u00AB不是为“1/2”和实际上这个:

http://www.fileformat.info/info/unic...r/ab/index.htm 那么什么字符Java中使用集,我还以为UNICODE应该就是这样,Uni,只有一个。我已经搜索了几个小时,无处可以找到一个指出/ u00AB等于1/2的字符集,但这正是我的java编译器解释的。

我必须在这里丢失一些明显的东西!谢谢你的帮助!

+3

我推荐这篇文章,以帮助理解你所面临的问题:绝对最低每一个软件开发人员绝对,积极必须知道的关于Unicode和字符集] (http://www.joelonsoftware.com/articles/Unicode.html) – 2011-01-20 13:26:04

回答

2

Java的一点很棒,就是它基于unicode。这意味着,您可以使用书写系统中不是英文字母(例如中文或数学符号)的字符,不仅在数据字符串中,而且在函数和变量名称中。

这是一个在类名和变量名中使用unicode字符的示例代码。

class 方 { 
    String 北 = "north"; 
    double π = 3.14159; 
} 

class UnicodeTest { 
    public static void main(String[] arg) { 
     方 x1 = new 方(); 
     System.out.println(x1.北); 
     System.out.println(x1.π); 
    } 
} 

Java是在Unicode标准为更小的一组字符定义值的时候创建的。那时候,人们感觉到16位将足以编码所有需要的字符。考虑到这一点,Java被设计为使用UTF-16。实际上,char数据类型最初用于表示16位Unicode代码点。

UTF-8字符集由RFC 2279指定;

的UTF-16字符集是由RFC 2781

指定UTF-16字符集使用16位值,并因此对字节顺序敏感。在这些编码中,流的字节顺序可以由Unicode字符'\ uFEFF'表示的初始字节顺序标记指示。字节顺序标记进行如下处理:

When decoding, the UTF-16BE and UTF-16LE charsets ignore byte-order marks; when encoding, they do not write byte-order marks. 

When decoding, the UTF-16 charset interprets a byte-order mark to indicate the byte order of the stream but defaults to big-endian if there is no byte-order mark; when encoding, it uses big-endian byte order and writes a big-endian byte-order mark. 

Also see this

+2

UTF-8和UTF-16 **不是**字符集;它们是两个不同的可变宽度编码** **非常相同的字符集:** Unicode。 – tchrist 2011-01-20 13:30:45

4

\u00ab字符不是1/2字符;请参阅Unicode.org网站的definitive code page

你看到的是(我认为)在默认字符编码不是UTF-8或Latin-1的平台上使用System.outPrintStream的后果。也许这是@ axtavt的答案建议的一些Windows字符集? (它也有,为什么\u00ab显示为1/2的一个合理的解释......而不是一些“图示”字。)

(在Unicode和拉丁-1,\00BD是为1/2字符码点)。

16

这是一个众所周知的问题与在Windows平台上的控制台编码不匹配。

Java运行时期望系统控制台使用的编码与系统默认编码相同。但是,Windows使用两个单独的编码:ANSI code page (system default encoding) and OEM code page (console encoding)

所以,当您尝试Unicode字符U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK写入控制台,Java运行时预计,控制台的编码是ANSI编码(即Windows-1252你的情况),在此Unicode字符表示为0xAB。但是,实际控制台编码是OEM编码(您的情况为CP437),其中0xAB表示。

因此,将数据打印到Windows控制台与System.out.println()会产生错误的结果。

要获得正确的结果,您可以使用System.console().writer().println()来代替。

+0

谢谢,这是有道理的,但你提到打印数据到Windows控制台会产生错误的结果。这个例子直接来自Java书,作者知道AB将是一半。这是否只是可怜的写作,他没有解释这一点? – Nick 2011-01-20 13:29:47

+1

@尼克:那么这是一个可怜的写作。也许作者很少使用非美国的ASCII字母,因此不熟悉这个问题。 – axtavt 2011-01-20 13:49:02

3

0xAB在老的Codepage 437中是1/2,这是Windows终端默认使用的,no matter what codepage you actually set。因此,实际上,char值代表Java程序的“«”字符,并且如果您在GUI中渲染该字符或在一个合理的操作系统上运行该字符,您将获得该字符。如果您还想在Windows中看到正确的输出,请将CMD中的字体设置从“栅格字体”切换(单击左上角的图标,属性,字体选项卡)。例如,与龙力控制台,我可以这样做:

C:\Users\Documents>java CharDemo 
131 
a + b is AB 
y is K and half is ½  

C:\Users\Documents>chcp 1252 
Active code page: 1252 

C:\Users\Documents>java CharDemo 
131 
a + b is AB 
y is K and half is « 

C:\Users\Documents>chcp 437 
Active code page: 437