Java Unicode混淆

Java Unicode混淆,java,unicode,Java,Unicode,嘿,大家好,我刚刚开始尝试学习Java,遇到了一些令人困惑的事情 我正在从我正在使用的书中打出一个例子。这是为了证明 字符数据类型 代码如下: 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

嘿,大家好,我刚刚开始尝试学习Java,遇到了一些令人困惑的事情

我正在从我正在使用的书中打出一个例子。这是为了证明 字符数据类型

代码如下:

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);
}
}
让我困惑的是语句char half='\u00AB'。书中指出\u00AB是符号“1/2”的代码。如上所述,当我从cmd编译和运行程序时,这一行上产生的符号实际上是一个“1/2”

因此,一切似乎都正常运转。我决定玩转代码,尝试一些不同的unicodes。我在谷歌上搜索了多个unicode表,发现它们都与上述结果不一致

在每一本书中,我发现它都说明代码/u00AB不是“1/2”,事实上是为了这个:

所以Java使用的是什么字符集,我认为UNicode应该是唯一的。我已经搜索了几个小时,没有任何地方可以找到状态/u00AB等于1/2的字符集,但这就是我的java编译器对它的解释


我一定错过了什么明显的东西!谢谢你的帮助

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.

字符
\u00ab
不是
1/2
字符;请参见Unicode.org网站

您看到的(我认为)是在默认字符编码不是UTF-8或拉丁语-1的平台上使用
System.out
PrintStream
的结果。也许是@axtavt的答案所建议的某个Windows字符集?(它还合理解释了为什么
\u00ab
显示为
1/2
…而不是某些“splat”字符。)


(在Unicode和Latin-1中,
\00BD
1/2
字符的码点。)

好吧,当我使用该代码时,我得到了这是一个众所周知的问题,Windows平台上的控制台编码不匹配

Java运行时希望系统控制台使用的编码与系统默认编码相同。但是,Windows使用两种不同的编码:

因此,当您尝试将Unicode字符
U+00AB左指双角度引号
写入控制台时,Java运行时希望控制台编码是ANSI编码(在您的示例中是这样),其中此Unicode字符表示为
0xAB
。但是,实际的控制台编码是OEM编码(在您的情况下),其中
0xAB
表示
½

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

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

0xAB是旧版的1/2,这是Windows终端默认使用的

因此,事实上,char值表示Java程序的“«”字符,如果您在GUI中呈现该字符或在sane操作系统上运行该字符,您将获得该字符。如果您还想在Windows中看到正确的输出,请将CMD中的字体设置从“光栅字体”(单击左上角的图标、属性、字体选项卡)切换到其他位置。例如,使用Lucida Console,我可以执行以下操作:

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

我推荐这篇文章来帮助理解您面临的问题:谢谢,这是有道理的,但是您提到将数据打印到windows控制台会产生错误的结果。这个例子直接来自一本Java书籍,作者知道AB是半个。这仅仅是因为他没有解释这一点而写得很差吗?@Nick:那么这是一篇很差的文章。也许作者很少使用非美国ascii字母,因此不熟悉这个问题。真的很傻。Java和Windows都使用在内存中编码为UTF-16LE的本机Unicode字符串。然而,如果不经过一个字符混乱的编码-解码循环,它们仍然无法相互交谈。UTF-8和UTF-16不是字符集;它们是两种完全相同字符集的不同可变宽度编码:Unicode。哦,如果你遇到你的书的作者,你会用它来击败他/她。有没有其他书的建议?当然,它必须从一开始就开始,从最基本的、最基本的开始。