为了账号安全,请及时绑定邮箱和手机立即绑定

char[] 到 byte[] 背后的 Java 11 Compact Strings 魔术

char[] 到 byte[] 背后的 Java 11 Compact Strings 魔术

慕田峪4524236 2022-07-20 12:13:56
在过去的两天里,我一直在阅读有关编码 Unicode Java 9 紧凑字符串的信息,我感觉很好。但是有些东西我不明白。关于字节数据类型1)。是一个 8 位存储范围从 -128 到 127问题1)。为什么Java没有像char unsigned 16 bits那样实现它?我的意思是它会在 0.256 的范围内,因为从 0 到 127 我只能保存一个 Ascii 值,但是如果我将值设置为 200 会发生什么,扩展的 ascii 会溢出到 -56。2)。负值是否意味着我的意思是我尝试了一个使用 Java 11 的简单示例final char value = (char)200;//in byte would overflowfinal String stringValue = new String(new char[]{value});System.out.println(stringValue);//THE SAME VALUE OF JAVA 8我检查了 String.value 变量,我看到了一个字节数组System.out.println(value[0]);//-56出现与之前相同的问题,-56 是否意味着其他语言中的(负值)这个溢出被检测到返回值 200?Java 怎么知道 -56 值与 char 中的 200 相同。我尝试了最难的例子,比如代码点 128048,我在 String.value 变量中看到了一个这样的字节数组。0 = 61 1 = -402 = 483 = -36我知道这个代码点需要 4 个字节,但我知道如何将 char[] 转换为 byte[] ,但我不知道 String 如何处理这个 byte[] 数据。对不起,如果这个问题很简单,对不起,任何打字英语都不是我的自然语言,非常感谢。
查看完整描述

2 回答

?
临摹微笑

TA贡献1982条经验 获得超2个赞

为什么Java没有像char unsigned 16 bits那样实现它?我的意思是它会在 0.256 的范围内,因为从 0 到 127 我只能保存一个 Ascii 值,但是如果我将值设置为 200 会发生什么,扩展的 ascii 会溢出到 -56。


Java 的原始数据类型在 25 年前的 Java 1.0 中得到了解决。不到两年前,Java 9 中引入了紧凑字符串。这个新特性只是一个实现细节,并不能证明 Java 类型系统的根本变化是合理的。


除此之外,您正在查看存储在一个字节中的数据的一种解释。为了表示 iso-latin-1 单位,将相同的数据解释为 Java 内置的 signedbyte是否会导致正数或负数完全无关紧要。


同样,Java 的 I/O API 允许将文件读入byte[]数组并将数组写byte[]回文件,这两个操作已经足以无损地复制文件,而不管其文件格式在解释其内容时是否相关。


所以从 Java 1.1 开始以下工作:


byte[] bytes = "È".getBytes("iso-8859-1");

System.out.println(bytes[0]);

System.out.println(bytes[0] & 0xff);

-56

200

这两个数字,-56和200只是位模式的不同解释,而包含位模式的11001000iso-latin-1 解释是字符。byte11001000È


值char也只是对两个字节数量的解释,即作为 UTF-16 代码单元。同样,char[]数组是计算机内存中具有标准解释的字节序列。


我们也可以用这种方式解释其他字节序列。


StringBuilder sb = new StringBuilder().appendCodePoint(128048);

byte[] array = new byte[4];

StandardCharsets.UTF_16LE.newEncoder()

    .encode(CharBuffer.wrap(sb), ByteBuffer.wrap(array), true);

System.out.println(Arrays.toString(array));

将打印您看到的值,[61, -40, 48, -36].


在类中使用byte[]数组的优点String是,现在可以选择解释,当所有字符都可以用这种编码表示时使用 iso-latin-1,否则使用 utf-16。


可能的数字解释与字符串无关。但是,当你问“Java 怎么知道 -56 值与 200 相同”时,你应该问自己,它是如何知道11001000abyte的位模式-56在首位的?


System.out.println(value[0]);

与普通计算机算术相比,a byte(或 an int)到 a的转换实际上是一个昂贵的操作String。这种转换操作经常被忽略,因为它已被定义为打印 a 的默认方式,但并不比将值解释为无符号数量byte的转换更自然。String为了进一步阅读,我推荐二进制补码。


查看完整回答
反对 回复 2022-07-20
?
jeck猫

TA贡献1909条经验 获得超7个赞

这是因为并非字符串中的所有字节都被解释为相同的。这取决于字符串的字符编码

例子:

  • 如果字符串是 UTF-8 字符串,则其字符大小为 8 位。

  • 在 UTF-16 字符串中,其字符大小为 16 位。

  • ETC...

这意味着,如果要将字符串表示为 UTF-8,则字符将通过一次读取 1 个字节来生成;如果是 16 位,则字符将通过一次读取 2 个字节来生成。

看这段代码:data使用 UTF-8 和 UTF-16 将单字节数组转换为字符串。

byte[] data = new byte[] {97, 98, 99, 100};

System.out.println(new String(data, StandardCharsets.UTF_8));

System.out.println(new String(data, StandardCharsets.UTF_16));

这段代码的输出是:


abcd // 4 bytes = 4 chars, 1 byte per char

慢捤  // 4 bytes = 2 chars, 2 byte per char

回到这个问题,开发人员这样做的动机是减少字符串的内存占用。并非所有字符串都使用所有 16 位 achar报价。


查看完整回答
反对 回复 2022-07-20
  • 2 回答
  • 0 关注
  • 121 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号