代码片段:
public static void main(String[] args) {
String s = "qwertyuiop";
System.out.println(Arrays.toString(Charset
.forName("UTF-8")
.encode(s)
.array()));
}
打印:
[113, 119, 101, 114, 116, 121, 117, 105, 111, 112, 0]
这似乎是因为,在幕后,对于 java.nio.charset.CharsetEncoder 类中的 UTF-8,averageBytesPerChar 变量似乎是 1.1。因此它分配了 11 个字节而不是 10 个字节,并且假设输入字符串只包含良好的旧单字节字符,我最后得到了那个奇怪的空字符。
我想知道这是否有任何记录?
本页:
https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html#encode(java.lang.String)
没有提供有关此类行为的线索。
P. S. 我是否理解正确,在任何情况下,上面的代码片段最好替换为:
s.getBytes(StandardCharsets.UTF_8)
正如我从其源代码中看到的那样,它还修剪了结果以避免那些空字符?
那么,java.nio.charset.Charset 的 encode(String s) 应该用来做什么?
最佳答案
问题不在Charset.encode()
,而是在Buffer.array()
。
如果你打印Charset.forName("UTF-8").encode(s)
,你会发现输出是
java.nio.HeapByteBuffer[pos=0 lim=10 cap=11]
ByteBuffer 的限制为 10,即字符串的长度,容量 为 11,即缓冲区的总分配大小。如果您更改编码,限制和容量可能会有更大的变化,例如
System.out.println(Charset.forName("UTF-16").encode(s));
// java.nio.HeapByteBuffer[pos=0 lim=22 cap=41]
// (2 extra bytes because of the BOM, not null-termination)
当你call .array()
,它将返回整个后备数组,因此即使超出限制的内容也会被包括在内。
提取Java字节数组的实际方法是通过the .get()
method :
ByteBuffer buf = Charset.forName("UTF-8").encode(s);
byte[] encoded = new byte[buf.limit()];
buf.get(encoded);
System.out.println(Arrays.toString(encoded));
这看起来很乱?因为“nio”的意思是Nativenative I/O。 Buffer 类型的创建使其可以轻松包装 C 数组。它使得与 native 代码的交互(例如读/写文件或发送/接收网络数据)变得非常高效。这些 NIO API 通常直接采用 Buffer
,而不会在两者之间构造任何 byte[]
。如果您只使用 Buffer
,则中间两行不需要存在 :)。
如果整个操作都在 Java 中,是的,只需调用 s.getBytes(StandardCharsets.UTF_8)
。
关于java - 将字符串编码为 UTF-8 字节时添加空字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42912994/