【问题标题】:Java get decimal byte representation of a characterJava获取字符的十进制字节表示
【发布时间】:2017-07-21 10:52:36
【问题描述】:

我有以下代码从字符串s0s1 中打印出字节;输出结果注释:

public static void main(String[] args) throws UnsupportedEncodingException {
    String s0="H\u00ebllo";
    String s1="Hëllo";

    byte[] bytes=s0.getBytes("ISO8859_1"); //72 -21 108 108 111
    //byte[] bytes=s1.getBytes("ISO8859_1"); //72 -61 -85 108 108 111
    //byte[] bytes=s0.getBytes("UTF-8");  //72 -61 -85 108 108 111
    //byte[] bytes=s1.getBytes("UTF-8");  //72 -61 -125 -62 -85 108 108 111
    for (int i=0,  i<bytes.length; i++)  {
        System.out.println(bytes[i]);
    }
}

我不明白这些数字是从哪里来的。如果所有字符代码都应该是正数,为什么会有负数?为什么第二种情况有6个数字?为什么使用 Unicode 表示法与文字时 ë 字符的数字不同?

编辑

我知道这些数字首先被转换为无符号数字:

ë(ISO8859_1) = 0xeb = 235 = 11101011 = -21 (two's complement for signed numbers)

ë (UTF-8) = 0xc3 0xab =&gt; 0xc3 = 195 = 11000011 = -61, 0xab = 171 = 10101011 = -85

但我仍然不明白s0s1 字符串之间的区别。在这两种情况下,我都向getBytes() 请求ISO8859_1 字节,而在第二种情况下,我仍然得到UTF-8 的字节。

编辑:

byte[] bytes=s1.getBytes("UTF-8"); 会产生这个输出:

72 -61 -125 -62 -85 108 108 111

我真的很困惑。

编辑

System.out.println(System.getProperty("file.encoding"));
System.out.println(java.nio.charset.Charset.defaultCharset());

两者都给UTF-8。源文件在UTF-8

【问题讨论】:

  • k的目的是什么?
  • @Andreas,这是一个更大计划的一部分,出于个人原因需要k。还是编辑了帖子。
  • 同样,您的源文件以 UTF-8 格式存储,因此 ë 存储为两个字节。您的编译器采用不同的编码并将 UTF-8 ë 误解为 ë,因此当代码执行时,它对 Hëllo 一无所知,而只知道 Hëllo
  • 内存中的字符串被编码为 UTF-16,而不是 UTF-8。文件编码和内存编码之间存在转换。通过将 String 视为字节序列,您无法可靠地获得正确的结果。您必须将其视为char 序列。 docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5
  • @Markus Benko,但 IDEA 说我的源文件以 UTF-8 (-Dfile.encoding=UTF-8) 运行,编译器是否使用不同的编码?

标签: java unicode encoding character-encoding ascii


【解决方案1】:

在 Java 中,byte 原始类型是signed,这意味着范围从 -128 到 +127(第一位被认为是数字的符号)。

在扩展 ASCII 和其他 8 位编码(如 ISO-8859-1)中,存在字节值大于 127 的字符。这些字符在打印为标准 Java byte 时将显示为负数。

如果您使用 UTF-8(或其他 Unicode UTF 编码),非 ASCII 字符由 2-4 个字节表示,并且每个字符都可能“大于 127”,因此它们将显示为当您将它们打印为 byte 值时,它们也是负数。

【讨论】:

  • 您能解释一下Java是如何从0xeb=235(011101011)中生成-21(111101011)的吗?这里使用的规则是什么?对于所有大于 127 的数字,通过将第一个零位 1 化为负数?
  • @parsecer 您要查找的是Two's complement 的描述,这是大多数计算机存储有符号整数的方式。
  • @parsecer 当您的源文件编码与编译器期望的不同时,您迟早会遇到严重的麻烦。这个答案的最后一段不正确,Java 中的字符串与 UTF-8 无关,String.getBytes("ISO8859_1") 永远不会为一个字符提供两个字节。
  • 第一位是信号。当它被翻转时,其余部分被认为是 2 的补码(翻转所有位并加 1)。所以 235 (11101011b) == 10000000b (信号) bit_OR 01101011b == 10000000b (信号) bit_OR NOT(0010100b + 1) == 10000000b (信号) bit_OR NOT(00010101b) == 10000000b (信号) OR NOT(信号)_ -21
【解决方案2】:

在 java 中,所有数字类型都是有符号(与无符号相反)。请注意,char 不是数字类型,即使它可以在算术上使用(滥用)。

您的编码给出了 -21,它只是 Java 的 byte 表示 0b111010110xEB

【讨论】:

【解决方案3】:

字节是 Java 中的有符号数字,范围为 -128 到 127。第二种情况有 6 个数字,因为您的源文件使用 UTF-8 编码,而 Java 编译器假定特定于平台的编码可能不是 UTF -8。使用 IDE 时,请查找与源代码和/或编译器编码对应的设置。使用javac 编译时,请尝试指定-encoding UTF-8

【讨论】:

  • ë 是 Unicode 的 U+00EB 并且是 ISO8859_1 中的 0xeb。 0xeb 应该是十进制的 235。
  • 使用 UTF-8 时,源代码中的 ë 作为字符串文字的一部分存储为两个字节。不,在 Java 中不存在任何应该是十进制 235 的 byte 值。
猜你喜欢
  • 1970-01-01
  • 2013-07-26
  • 2018-08-07
  • 2014-12-20
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 2012-09-13
  • 1970-01-01
相关资源
最近更新 更多