Java char[] 到 byte[] 背后的 11 个压缩字符串魔法
Java 11 Compact Strings magic behind char[] to byte[]
最近两天我一直在阅读有关编码 Unicode Java 9 compact Strings 的文章,我感觉很好。但是有一点我不明白。
关于字节数据类型
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 overflow
final 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 是否意味着我的意思(负值)在其他语言中这个溢出被检测到 return 到值 200? Java 怎么知道 -56 值和 char.
中的 200 是一样的
我尝试了最困难的示例,例如代码点 128048,我在 String.value 变量中看到了这样的字节数组。
0 = 61
1 = -40
2 = 48
3 = -36
我知道这个代码点需要 4 个字节,但我知道它是如何将 char[] 转换为 byte[] 但我不知道 String 如何处理这个 byte[] 数据。
很抱歉,如果这个问题很简单,很抱歉打字英语不是我的母语,非常感谢。
这是因为并非字符串中的所有字节都被解释为相同的。这取决于字符串的 character encoding.
示例:
- 如果字符串是 UTF-8 字符串,其字符大小为 8 位。
- 在 UTF-16 字符串中,其字符大小为 16 位。
- 等...
这意味着,如果要将字符串表示为UTF-8,则字符将通过一次读取1个字节来生成;如果是 16 位,字符将通过一次读取 2 个字节来组成。
看这段代码:使用 UTF-8 和 UTF-16 将单字节数组 data
转换为字符串。
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
回到问题,开发人员这样做的动机是减少字符串的内存占用。并非所有字符串都使用 char
提供的所有 16 位。
编辑:Code here
Why Java didn't implement it like char unsigned 16 bits? i mean it would be in a range of 0.256 because from 0 to 127 only can i hold a Ascii value but what would happen if i set the value 200 a extended ascii would overflow to -56.
Java 的原始数据类型在四分之一个世纪前由 Java 1.0 解决。压缩字符串是在不到两年前的 Java 9 中引入的。这个新功能只是一个实现细节,并不能证明 Java 类型系统的根本变化是合理的。
除此之外,您正在查看存储在一个字节中的数据的一个解释。为了表示 iso-latin-1 单位,将相同的数据解释为 Java 的内置符号 byte
会导致正数还是负数完全无关紧要。
同样 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
这两个数字只是对位模式 11001000
的不同解释,而 byte
的 iso-latin-1 解释包含位模式 11001000
是字符 È
.
A 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]
。
在 String
class 中使用 byte[]
数组的好处是,现在可以选择解释,当所有字符都是 iso-latin-1 时可以使用此编码或 utf-16 表示。
可能的数字解释与字符串无关。然而,当你问“Java如何知道-56值与200相同”时,你应该问自己,它如何知道byte
的位模式11001000
-56
排在首位吗?
System.out.println(value[0]);
与普通计算机算术相比, 承担了一项实际昂贵的操作,将 byte
(或 int
)转换为 String
。这种转换操作经常被忽视,因为它被定义为打印 byte
的默认方式,但并不比将值解释为无符号数量的 String
转换更自然。如需进一步阅读,我推荐 Two's complement.
最近两天我一直在阅读有关编码 Unicode Java 9 compact Strings 的文章,我感觉很好。但是有一点我不明白。
关于字节数据类型
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 overflow
final 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 是否意味着我的意思(负值)在其他语言中这个溢出被检测到 return 到值 200? Java 怎么知道 -56 值和 char.
中的 200 是一样的我尝试了最困难的示例,例如代码点 128048,我在 String.value 变量中看到了这样的字节数组。
0 = 61
1 = -40
2 = 48
3 = -36
我知道这个代码点需要 4 个字节,但我知道它是如何将 char[] 转换为 byte[] 但我不知道 String 如何处理这个 byte[] 数据。
很抱歉,如果这个问题很简单,很抱歉打字英语不是我的母语,非常感谢。
这是因为并非字符串中的所有字节都被解释为相同的。这取决于字符串的 character encoding.
示例:
- 如果字符串是 UTF-8 字符串,其字符大小为 8 位。
- 在 UTF-16 字符串中,其字符大小为 16 位。
- 等...
这意味着,如果要将字符串表示为UTF-8,则字符将通过一次读取1个字节来生成;如果是 16 位,字符将通过一次读取 2 个字节来组成。
看这段代码:使用 UTF-8 和 UTF-16 将单字节数组 data
转换为字符串。
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
回到问题,开发人员这样做的动机是减少字符串的内存占用。并非所有字符串都使用 char
提供的所有 16 位。
编辑:Code here
Why Java didn't implement it like char unsigned 16 bits? i mean it would be in a range of 0.256 because from 0 to 127 only can i hold a Ascii value but what would happen if i set the value 200 a extended ascii would overflow to -56.
Java 的原始数据类型在四分之一个世纪前由 Java 1.0 解决。压缩字符串是在不到两年前的 Java 9 中引入的。这个新功能只是一个实现细节,并不能证明 Java 类型系统的根本变化是合理的。
除此之外,您正在查看存储在一个字节中的数据的一个解释。为了表示 iso-latin-1 单位,将相同的数据解释为 Java 的内置符号 byte
会导致正数还是负数完全无关紧要。
同样 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
这两个数字只是对位模式 11001000
的不同解释,而 byte
的 iso-latin-1 解释包含位模式 11001000
是字符 È
.
A 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]
。
在 String
class 中使用 byte[]
数组的好处是,现在可以选择解释,当所有字符都是 iso-latin-1 时可以使用此编码或 utf-16 表示。
可能的数字解释与字符串无关。然而,当你问“Java如何知道-56值与200相同”时,你应该问自己,它如何知道byte
的位模式11001000
-56
排在首位吗?
System.out.println(value[0]);
与普通计算机算术相比, 承担了一项实际昂贵的操作,将 byte
(或 int
)转换为 String
。这种转换操作经常被忽视,因为它被定义为打印 byte
的默认方式,但并不比将值解释为无符号数量的 String
转换更自然。如需进一步阅读,我推荐 Two's complement.