Java 8 UTF-16 不是默认字符集,而是 UTF-8

标签 java string utf-8 utf-16

我一直在 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??

在简历中。

  1. 为什么 UTF-16 总是有两个前导字节,它们浪费了吗?新字节[]{-1,-2}

  2. 为什么当我编码“È”时,我在 ASCCI 字符集中没有得到任何字节,但当我编码 È.getBytes(StandardCharsets.US_ASCII) 时,我得到 {63}?

  3. 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/

相关文章:

java - 如何在android中创建两个固定大小的 View 和跨越它们之间的一个 View ?

java - 在java中用另一个字符串替换字符串

c# - 如何在 C# 中将拆分字符串(字符串数组)转换为 double 字符串?

c++ - 让 API 使用 std::string 作为错误代码返回是不好的做法吗?

utf-8 - JXA : Set UTF-8 encoding when writing files

ruby - 如何将 UCS2 字符串转换为 UTF8?

java - Spark RDD MEMORY_AND_DISK_2() 中的存储级别抛出异常

java - .Net 客户端 - 使用 tls1.2 的 Java 服务器连接问题

php - 我无法解决的 MySQL 错误

java - 如何检测安卓手机是否有双后置摄像头