我一直在 Java8、Java 11 中使用 String 进行一些编码,但这个问题是基于 Java 8 的。我有这个小片段。
final char e = (char)200;//È
我只是认为 0.255[Ascii+扩展 Ascii] 之间的字符总是适合一个字节,因为 2^8=256 但这似乎不是真的,我在网站 https://mothereff.in/byte-counter 上尝试过并指出该字符占用 2 个字节,有人可以向我解释一下吗?
很多帖子中的另一个问题指出 Java 是 UTF-16,但在我运行 Windows 7 的机器中,此代码段返回 UTF-8。
String csn = Charset.defaultCharset().name();
这个平台是否依赖?
我尝试过此代码片段的其他问题。
final List<Charset>charsets = Arrays.asList(StandardCharsets.ISO_8859_1,StandardCharsets.US_ASCII,StandardCharsets.UTF_16,StandardCharsets.UTF_8);
charsets.forEach(a->print(a,"È"));
System.out.println("getBytes");
System.out.println(Arrays.toString("È".getBytes()));
charsets.forEach(a->System.out.println(a+" "+Arrays.toString(sb.toString().getBytes(a))));
private void print(final Charset set,final CharSequence sb){
byte[] array = new byte[4];
set.newEncoder()
.encode(CharBuffer.wrap(sb), ByteBuffer.wrap(array), true);
final String buildedString = new String(array,set);
System.out.println(set+" "+Arrays.toString(array)+" "+buildedString+"<<>>"+buildedString.length());
}
和打印
run:
ISO-8859-1 [-56, 0, 0, 0] È//PERFECT USING 1 BYTE WHICH IS -56
US-ASCII [0, 0, 0, 0] //DONT GET IT SEE THIS ITEM FOR LATER
UTF-16 [-2, -1, 0, -56] È<<>>1 //WHAT IS -2,-1 BYTE USED FOR? I HAVE TRY WITH OTHER EXAMPLES AND THEY ALWAYS APPEAR AM I LOSING TWO BYTES HERE??
UTF-8 [-61, -120, 0, 0] 2 È //SEEMS TO MY CHARACTER NEEDS TWO BYTES?? I THOUGHT THAT CODE=200 WOULD REQUIRE ONLY ONE
getBytes
[-61, -120]//OK MY UTF-8 REPRESENTATION
ISO-8859-1 [-56]//OK
US-ASCII [63]//OK BUT WHY WHEN I ENCODE IN ASCCI DOESNT GET ANY BYTE ENCODED?
UTF-16 [-2, -1, 0, -56]//AGAIN WHAT ARE -2,-1 IN THE LEADING BYTES?
UTF-8 [-61, -120]//OK
我已经尝试过
System.out.println(new String(new byte[]{-1,-2},"UTF-16"));//SIMPLE "" I AM WASTING THIS 2 BYTES??
在简历中。
为什么 UTF-16 总是有两个前导字节,它们浪费了吗?新字节[]{-1,-2}
为什么当我编码“È”时,我在 ASCCI 字符集中没有得到任何字节,但当我编码 È.getBytes(StandardCharsets.US_ASCII) 时,我得到 {63}?
Java 使用 UTF-16,但就我而言,UTF-8 取决于平台?
抱歉,如果这篇文章令人困惑
环境
Windows 7 64 Bits Netbeans 8.2 with Java 1.8.0_121
最佳答案
第一个问题
对于您的第一个问题:这些字节是 BOM 代码,它们指定多字节编码(例如 UTF-16)的字节顺序(无论是最低位还是最高位在前)。
第二个问题
每个 ASCII 字符都可以编码为 UTF-8 中的单个字节。但 ASCII 不是 8 位编码,它每个字符使用 7 位。事实上,所有代码点 >= 128 的 Unicode 字符都需要至少两个字节。 (原因是您需要一种方法来区分 200 和第一个字节恰好是 200 的多字节代码点。UTF-8 通过使用 >= 128 的字节来表示多字节代码点来解决这个问题。)
“È”不是 ASCII 字符,因此不能用 ASCII 表示。这解释了第二个输出:63 是字符“?”的 ASCII。事实上,getBytes(Charset)
方法的 Javadoc 指定将不可映射的输入映射到“默认替换字节数组”,在本例中为“?”。另一方面,要获取第一个 ASCII 字节数组,您可以直接使用 CharsetEncoder
,这是一个更底层的 API,不会执行此类自动替换。 (当您检查 encode
方法的结果时,您会发现它返回了一个表示错误的 CoderResult
实例。)
第三个问题
Java 8 String
内部使用 UTF-16,但与其他软件通信时,可能需要不同的编码,例如 UTF-8。 Charset.defaultCharset()
方法返回虚拟机的默认字符集,该字符集取决于操作系统的语言环境和字符集,而不取决于 Java 字符串内部使用的编码。
关于Java 8 UTF-16 不是默认字符集,而是 UTF-8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55088169/