Java 8 UTF-16 不是默认字符集而是 UTF-8
Java 8 UTF-16 isn't default charset but UTF-8
我在 Java8、Java 11 中使用字符串进行了一些编码,但这个问题基于 Java 8。我有这个小片段。
final char e = (char)200;//È
我只是认为 0.255[Ascii+extended Ascii] 之间的字符总是适合一个字节,因为 2^8=256 但这似乎不是真的我在网站上试过 https://mothereff.in/byte-counter并声明该字符占用 2 个字节,有人可以向我解释一下吗。
很多 post 中的另一个问题指出 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 是平台依赖的??
抱歉,如果post令人困惑
环境
Windows 7 64 Bits Netbeans 8.2 with Java 1.8.0_121
让我们后退一点……
Java 的文本数据类型使用 Unicode 字符集的 UTF-16 字符编码。 (和 VB4/5/6/A/Script、JavaScript、.NET 一样……)您可以在对字符串 API 执行的各种操作中看到这一点:索引、长度、……
库支持使用各种编码在文本数据类型和字节数组之间进行转换。其中一些被归类为 "Extended ASCII",但声明这是一个非常糟糕的替代命名实际使用的字符编码。
一些操作系统允许用户指定默认字符编码。 (不过,大多数用户不知道或不在乎。)Java 试图了解这一点。只有当程序理解用户的输入是字符编码或输出应该是时,它才有用。本世纪,处理文本文件的用户更喜欢使用特定的编码,在系统之间以不变的方式进行通信,不喜欢有损转换,因此这个概念没有任何用处。从程序的角度来看,它永远不是你想要的,除非它正是你想要的。
在转换有损的情况下,您可以选择替换字符(如“?”)、忽略它或抛出异常。
根据编码的定义,字符编码是字符集的代码点(整数)与一个或多个代码单元之间的映射。代码单元的大小是固定的,代码点所需的代码单元数量可能因代码点而异。
在库中,拥有一组代码单元通常没有用,因此它们采取进一步的步骤将 to/from 转换为字节数组。 byte
值的范围从 -128 到 127,但是,Java 将其解释为 2 的补码 8 位整数。由于字节被理解为编码文本,因此值将根据字符编码规则进行解释。
由于某些 Unicode 编码的代码单元长度超过一个字节,因此字节顺序变得很重要。所以,在字节数组级别,有 UTF-16 Big Endian 和 UTF-16 Little Endian。在传输文本文件或流时,您将发送字节并共享编码知识。这个"metadata"是理解所必需的。例如,UTF-16BE 或 UTF-16LE。为了使这更容易一些,Unicode 允许文件或流的一些元数据开头来指示字节顺序。它被称为字节顺序标记 (BOM) 因此,外部元数据可以共享编码(例如 UTF-16),而内部元数据共享字节顺序。即使字节顺序不相关,Unicode 也允许 BOM 存在,例如 UTF-8。因此,如果理解为字节是使用任何 Unicode 编码进行编码的文本并且存在 BOM,那么如果相关的话,找出它是哪种 Unicode 编码以及字节顺序是什么是一件非常简单的事情。
1) 您在某些 Unicode 编码输出中看到了 BOM。
2) È不在ASCII字符集中。在这种情况下会发生什么?我通常更喜欢例外。
3) 您在测试时为您的帐户使用的系统可能已将 UTF-8 作为默认字符编码,这对您想要的方式和对文本文件的编码方式很重要在那个系统上?
第一题
对于您的第一个问题:这些字节是 BOM 代码,它们指定多字节编码(例如 UTF-16)的字节顺序(无论是最低位还是最高位在前)。
第二题
每个 ASCII 字符都可以在 UTF-8 中编码为单个字节。但是 ASCII 不是 8 位编码,它每个字符使用 7 位。事实上,所有代码点 >= 128 的 Unicode 字符都需要至少两个字节。 (原因是您需要一种方法来区分 200 和第一个字节恰好是 200 的多字节代码点。UTF-8 通过使用字节 >= 128 来表示多字节代码点来解决这个问题。)
'È'不是ASCII字符,所以不能用ASCII表示。这解释了第二个输出:63 是字符“?”的 ASCII。事实上,getBytes(Charset)
方法的 Javadoc 指定不可映射的输入映射到 "the default replacement byte array",在本例中为“?”。另一方面,要获得第一个 ASCII 字节数组,您直接使用了 CharsetEncoder
,这是一个更底层的 API,不会执行此类自动替换。 (当您检查 encode
方法的结果时,您会发现它返回了一个表示错误的 CoderResult
实例。)
第三题
Java 8 String
内部使用UTF-16,但与其他软件通信时,可能需要不同的编码,例如UTF-8。 Charset.defaultCharset()
方法 returns 虚拟机的默认字符集,这取决于操作系统的语言环境和字符集,而不取决于 Java 字符串内部使用的编码。
我在 Java8、Java 11 中使用字符串进行了一些编码,但这个问题基于 Java 8。我有这个小片段。
final char e = (char)200;//È
我只是认为 0.255[Ascii+extended Ascii] 之间的字符总是适合一个字节,因为 2^8=256 但这似乎不是真的我在网站上试过 https://mothereff.in/byte-counter并声明该字符占用 2 个字节,有人可以向我解释一下吗。
很多 post 中的另一个问题指出 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 是平台依赖的??
抱歉,如果post令人困惑
环境
Windows 7 64 Bits Netbeans 8.2 with Java 1.8.0_121
让我们后退一点……
Java 的文本数据类型使用 Unicode 字符集的 UTF-16 字符编码。 (和 VB4/5/6/A/Script、JavaScript、.NET 一样……)您可以在对字符串 API 执行的各种操作中看到这一点:索引、长度、……
库支持使用各种编码在文本数据类型和字节数组之间进行转换。其中一些被归类为 "Extended ASCII",但声明这是一个非常糟糕的替代命名实际使用的字符编码。
一些操作系统允许用户指定默认字符编码。 (不过,大多数用户不知道或不在乎。)Java 试图了解这一点。只有当程序理解用户的输入是字符编码或输出应该是时,它才有用。本世纪,处理文本文件的用户更喜欢使用特定的编码,在系统之间以不变的方式进行通信,不喜欢有损转换,因此这个概念没有任何用处。从程序的角度来看,它永远不是你想要的,除非它正是你想要的。
在转换有损的情况下,您可以选择替换字符(如“?”)、忽略它或抛出异常。
根据编码的定义,字符编码是字符集的代码点(整数)与一个或多个代码单元之间的映射。代码单元的大小是固定的,代码点所需的代码单元数量可能因代码点而异。
在库中,拥有一组代码单元通常没有用,因此它们采取进一步的步骤将 to/from 转换为字节数组。 byte
值的范围从 -128 到 127,但是,Java 将其解释为 2 的补码 8 位整数。由于字节被理解为编码文本,因此值将根据字符编码规则进行解释。
由于某些 Unicode 编码的代码单元长度超过一个字节,因此字节顺序变得很重要。所以,在字节数组级别,有 UTF-16 Big Endian 和 UTF-16 Little Endian。在传输文本文件或流时,您将发送字节并共享编码知识。这个"metadata"是理解所必需的。例如,UTF-16BE 或 UTF-16LE。为了使这更容易一些,Unicode 允许文件或流的一些元数据开头来指示字节顺序。它被称为字节顺序标记 (BOM) 因此,外部元数据可以共享编码(例如 UTF-16),而内部元数据共享字节顺序。即使字节顺序不相关,Unicode 也允许 BOM 存在,例如 UTF-8。因此,如果理解为字节是使用任何 Unicode 编码进行编码的文本并且存在 BOM,那么如果相关的话,找出它是哪种 Unicode 编码以及字节顺序是什么是一件非常简单的事情。
1) 您在某些 Unicode 编码输出中看到了 BOM。
2) È不在ASCII字符集中。在这种情况下会发生什么?我通常更喜欢例外。
3) 您在测试时为您的帐户使用的系统可能已将 UTF-8 作为默认字符编码,这对您想要的方式和对文本文件的编码方式很重要在那个系统上?
第一题
对于您的第一个问题:这些字节是 BOM 代码,它们指定多字节编码(例如 UTF-16)的字节顺序(无论是最低位还是最高位在前)。
第二题
每个 ASCII 字符都可以在 UTF-8 中编码为单个字节。但是 ASCII 不是 8 位编码,它每个字符使用 7 位。事实上,所有代码点 >= 128 的 Unicode 字符都需要至少两个字节。 (原因是您需要一种方法来区分 200 和第一个字节恰好是 200 的多字节代码点。UTF-8 通过使用字节 >= 128 来表示多字节代码点来解决这个问题。)
'È'不是ASCII字符,所以不能用ASCII表示。这解释了第二个输出:63 是字符“?”的 ASCII。事实上,getBytes(Charset)
方法的 Javadoc 指定不可映射的输入映射到 "the default replacement byte array",在本例中为“?”。另一方面,要获得第一个 ASCII 字节数组,您直接使用了 CharsetEncoder
,这是一个更底层的 API,不会执行此类自动替换。 (当您检查 encode
方法的结果时,您会发现它返回了一个表示错误的 CoderResult
实例。)
第三题
Java 8 String
内部使用UTF-16,但与其他软件通信时,可能需要不同的编码,例如UTF-8。 Charset.defaultCharset()
方法 returns 虚拟机的默认字符集,这取决于操作系统的语言环境和字符集,而不取决于 Java 字符串内部使用的编码。