将 int 转换为 char 然后再转换回 int - 并不总是给出相同的结果
Converting a int to char and then back to int - doesn't give same result always
我正在尝试从 int
值 > 0xFFFF
中获取 char
。但相反,我总是得到相同的 char
值,当转换为 int
时,打印值 65535
(0xFFFF
).
我不明白为什么它会为 unicode > 0xFFFF
.
生成符号
int hex = 0x10FFFF;
char c = (char)hex;
System.out.println((int)c);
我预计输出为 0x10FFFF
。相反,输出返回为 65535
.
这是因为,int
是 4 个字节,而 char
只有 2 个字节。因此,您不能像在 int
中那样在 char
中表示所有值。使用标准的无符号整数表示,您只能用 2 字节值表示从 0
到 2^16 - 1 == 65535
的值范围,因此如果您将该范围外的任何数字转换为 2 字节值并且回来,你会丢失数据。
int 是 4 个字节。 char 是 2 个字节。
您的号码完全在 int 可以容纳的范围内,但不是 which char 可以容纳的范围。
因此,当您将该数字转换为 char 时,它会丢失数据并成为 char 可以容纳的最大值,这就是它打印的内容,即 65535
您的数字太大,不能是 2 个字节的字符。但它足够小,适合作为 4 个字节的 int。 65535 是适合 char 的最大数量,因此这就是您获得该值的原因。此外,如果 char 足够大以适合您的数字,当您将它返回到 int 时,它可能返回 0x10FFFF 的十进制值,即 1114111.
不幸的是,我认为您期望 Java char
与 Unicode 代码点相同。它们不是一回事。
Javachar
,其他答案已经表示,只能支持16位可以表示的码位,而Unicode需要21位才能支持所有码位。
换句话说,Java char
本身只支持基本多语言平面字符(代码点 <= 0xFFFF
)。在 Java 中,如果你想表示一个扩展平面中的 Unicode 代码点(代码点 > 0xFFFF
),那么你需要代理字符或一对字符来做到这一点。这就是 UTF-16 的工作原理。而且,在内部,这也是 Java 字符串的工作方式。只是为了好玩,运行 下面的代码片段可以看到如果代码点是 > 0xFFFF
:
,单个 Unicode 代码点实际上是如何由 2 个字符表示的
// Printing string length for a string with
// a single unicode code point: 0x22BED.
System.out.println("".length()); // prints 2, because it uses a surrogate pair.
如果您想安全地将表示 Unicode 代码点的 int
值转换为 char
(或更准确地说是 char
s),然后再将其转换回来到 int
代码点,您将必须使用这样的代码:
public static void main(String[] args) {
int hex = 0x10FFFF;
System.out.println(Character.isSupplementaryCodePoint(hex)); // prints true because hex > 0xFFFF
char[] surrogateChars = Character.toChars(hex);
int codePointConvertedBack = Character.codePointAt(surrogateChars, 0);
System.out.println(codePointConvertedBack); // prints 1114111
}
或者,您可以使用 String
,而不是操作 char
数组,如下所示:
public static void main(String[] args) {
int hex = 0x10FFFF;
System.out.println(Character.isSupplementaryCodePoint(hex)); // prints true because hex > 0xFFFF
String s = new String(new int[] {hex}, 0, 1);
int codePointConvertedBack = s.codePointAt(0);
System.out.println(codePointConvertedBack); // prints 1114111
}
进一步阅读:Java Character Class
我正在尝试从 int
值 > 0xFFFF
中获取 char
。但相反,我总是得到相同的 char
值,当转换为 int
时,打印值 65535
(0xFFFF
).
我不明白为什么它会为 unicode > 0xFFFF
.
int hex = 0x10FFFF;
char c = (char)hex;
System.out.println((int)c);
我预计输出为 0x10FFFF
。相反,输出返回为 65535
.
这是因为,int
是 4 个字节,而 char
只有 2 个字节。因此,您不能像在 int
中那样在 char
中表示所有值。使用标准的无符号整数表示,您只能用 2 字节值表示从 0
到 2^16 - 1 == 65535
的值范围,因此如果您将该范围外的任何数字转换为 2 字节值并且回来,你会丢失数据。
int 是 4 个字节。 char 是 2 个字节。 您的号码完全在 int 可以容纳的范围内,但不是 which char 可以容纳的范围。 因此,当您将该数字转换为 char 时,它会丢失数据并成为 char 可以容纳的最大值,这就是它打印的内容,即 65535
您的数字太大,不能是 2 个字节的字符。但它足够小,适合作为 4 个字节的 int。 65535 是适合 char 的最大数量,因此这就是您获得该值的原因。此外,如果 char 足够大以适合您的数字,当您将它返回到 int 时,它可能返回 0x10FFFF 的十进制值,即 1114111.
不幸的是,我认为您期望 Java char
与 Unicode 代码点相同。它们不是一回事。
Javachar
,其他答案已经表示,只能支持16位可以表示的码位,而Unicode需要21位才能支持所有码位。
换句话说,Java char
本身只支持基本多语言平面字符(代码点 <= 0xFFFF
)。在 Java 中,如果你想表示一个扩展平面中的 Unicode 代码点(代码点 > 0xFFFF
),那么你需要代理字符或一对字符来做到这一点。这就是 UTF-16 的工作原理。而且,在内部,这也是 Java 字符串的工作方式。只是为了好玩,运行 下面的代码片段可以看到如果代码点是 > 0xFFFF
:
// Printing string length for a string with
// a single unicode code point: 0x22BED.
System.out.println("".length()); // prints 2, because it uses a surrogate pair.
如果您想安全地将表示 Unicode 代码点的 int
值转换为 char
(或更准确地说是 char
s),然后再将其转换回来到 int
代码点,您将必须使用这样的代码:
public static void main(String[] args) {
int hex = 0x10FFFF;
System.out.println(Character.isSupplementaryCodePoint(hex)); // prints true because hex > 0xFFFF
char[] surrogateChars = Character.toChars(hex);
int codePointConvertedBack = Character.codePointAt(surrogateChars, 0);
System.out.println(codePointConvertedBack); // prints 1114111
}
或者,您可以使用 String
,而不是操作 char
数组,如下所示:
public static void main(String[] args) {
int hex = 0x10FFFF;
System.out.println(Character.isSupplementaryCodePoint(hex)); // prints true because hex > 0xFFFF
String s = new String(new int[] {hex}, 0, 1);
int codePointConvertedBack = s.codePointAt(0);
System.out.println(codePointConvertedBack); // prints 1114111
}
进一步阅读:Java Character Class