我一直在Java8,Java 11中使用String进行编码,但是这个问题是基于Java 8的。
final char e = (char)200;//È
我只是认为0.255 [Ascii + extended 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
答案 0 :(得分:1)
让我们备份一下...
Java的文本数据类型使用Unicode字符集的UTF-16字符编码。 (和VB4 / 5/6 / A / Script,JavaScript,.NET等一样。)您可以在使用字符串API进行的各种操作中看到这一点:索引,长度等。
库支持使用各种编码在文本数据类型和字节数组之间进行转换。其中一些被归类为“扩展的ASCII”,但指出这是命名实际使用的字符编码的一种非常差的替代方法。
某些操作系统允许用户指定默认字符编码。 (不过,大多数用户不知道或不在乎。)Java尝试对此进行处理。仅当程序理解用户输入的内容是字符编码或输出应该是有用的时,它才有用。本世纪,处理文本文件的用户更喜欢使用特定的编码,在系统之间进行不变的通信,不欣赏有损的转换,因此对该概念没有任何用处。从程序的角度来看,它永远不是您想要的,除非它确实是您想要的。
如果转换会造成损失,则可以选择替换字符(例如“?”),可以省略替换字符或引发异常。
根据编码的定义,字符编码是字符集的代码点(整数)和一个或多个代码单元之间的映射。代码单位是固定大小,一个代码点所需的代码单位数可能会因代码点而异。
在库中,通常没有代码单元数组,因此它们采取进一步的步骤来与字节数组进行相互转换。 byte
的值的范围从-128到127,但这是Java解释为二进制补码8位整数。由于字节被理解为编码文本,因此将根据字符编码的规则来解释这些值。
由于某些Unicode编码的代码单元超过一个字节长,因此字节顺序变得很重要。因此,在字节数组级别上,有UTF-16 Big Endian和UTF-16 Little Endian。在传递文本文件或流时,您将发送字节并共享编码知识。理解需要此“元数据”。因此,例如,UTF-16BE或UTF-16LE。为了使操作更简单,Unicode允许文件或流的某些元数据开头指示字节顺序。它称为字节顺序标记(BOM),因此,外部元数据可以共享编码(例如UTF-16),而内部元数据则共享字节顺序。 Unicode允许BOM出现,即使字节顺序不相关,例如UTF-8。因此,如果理解为字节是使用任何Unicode编码进行文本编码的,并且存在BOM表,那么弄清楚它是哪种Unicode编码以及字节顺序是什么就很简单了。
1)您正在某些Unicode编码输出中看到BOM。
2)È不在ASCII字符集中。在这种情况下会发生什么?我经常更喜欢例外。
3)您在测试时所使用的帐户系统可能已将UTF-8作为默认字符编码,这对您想要的方式是否很重要,并已在该系统上对文本文件进行了编码系统吗?
答案 1 :(得分:1)
第一个问题
第一个问题:这些字节是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字符串内部使用的编码。