Java使用UTF-8或UTF-16编码?

Nit*_*waj 6 java encoding default utf-8 utf-16

我已经阅读了以下帖子:

  1. 什么是Java的String内部代表?修改过的UTF-8?UTF-16?
  2. https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

现在考虑下面给出的代码:

public static void main(String[] args) {
    printCharacterDetails("?");
}

public static void printCharacterDetails(String character){
    System.out.println("Unicode Value for "+character+"="+Integer.toHexString(character.codePointAt(0)));
    byte[] bytes = character.getBytes();
    System.out.println("The UTF-8 Character="+character+"  | Default: Number of Bytes="+bytes.length);
    String stringUTF16 = new String(bytes, StandardCharsets.UTF_16);
    System.out.println("The corresponding UTF-16 Character="+stringUTF16+"  | UTF-16: Number of Bytes="+stringUTF16.getBytes().length);
    System.out.println("----------------------------------------------------------------------------------------");
}
Run Code Online (Sandbox Code Playgroud)

当我尝试character.getBytes()在上面的代码中调试行时,调试器将我带入getBytes()String类的方法,然后进入static byte[] encode(char[] ca, int off, int len)StringCoding类的方法.String csn = Charset.defaultCharset().name();在调试过程中,encode method()的第一行返回"UTF-8"作为默认编码.我预计它会是"UTF-16".

该计划的输出是:

最大的Unicode值= 6700 UTF-8字符=最| 默认值:字节数= 3

相应的UTF-16字符= | UTF-16:字节数= 6

当我在程序中明确地将其转换为UTF-16时,花费了6个字节来表示该字符.不应该为UTF-16使用2或4个字节吗?为什么使用6个字节?

我的理解在哪里出错了?我使用Ubuntu 14.04,locale命令显示以下内容:

LANG=en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)

这是否意味着JVM决定在底层操作系统的基础上使用哪种编码,还是仅使用UTF-16?请帮我理解这个概念.

Rea*_*tic 15

人物是一种图形实体,是人类文化的一部分.当一台计算机需要处理的文本,它采用了代表字节这些字符.使用的确切表示称为编码.

有许多编码可以表示相同的字符 - 通过Unicode字符集,或通过其他字符集,如各种ISO-8859编码,或JIS X 0208.

在内部,Java使用UTF-16.这意味着每个字符可以由两个字节的一个或两个序列表示.您使用的字符,最大,代码点为U + 6700,以UTF-16表示为字节0x67和字节0x00.

这是内部编码.除非转储内存并查看转储映像中的字节,否则无法看到它.

但这种方法getBytes()没有返回这个内部表示.它的文件说:

public byte[] getBytes()

String使用平台的默认字符集将其编码为字节序列,将结果存储到新的字节数组中.

"平台的默认字符集"是您的语言环境变量所说的.就是这样UTF-8.因此它采用UTF-16内部表示,并将其转换为不同的表示形式 - UTF-8.

注意

new String(bytes, StandardCharsets.UTF_16);
Run Code Online (Sandbox Code Playgroud)

没有 "将其转换为UTF-16明确"当你认为它.此字符串构造函数采用一系列字节,这些字节应该是您在第二个参数中给出的编码,并将其转换为该字节在该编码中表示的任何字符的UTF-16表示形式.

但是你已经给它一个以UTF-8编码的字节序列,并告诉它将其解释为UTF-16.这是错误的,你没有得到你期望的字符 - 或字节 - .

您无法告诉Java如何在内部存储字符串.它总是将它们存储为UTF-16.构造函数String(byte[],Charset)告诉Java从应该在给定字符集中的字节数组创建UTF-16字符串.该方法getBytes(Charset)告诉Java为您提供一个字节序列,表示给定编码(charset)中的字符串.getBytes()没有参数的方法也是如此 - 但是使用平台的默认字符集进行转换.

所以你误解了是什么getBytes()给了你.这不是内部代表.你不能直接得到它.只会getBytes(StandardCharsets.UTF_16)因为你知道这UTF-16是Java中的内部表示而给你这个.如果Java的未来版本决定以不同的编码表示字符,则getBytes(StandardCharsets.UTF_16)不会向您显示内部表示.

编辑:事实上,Java 9引入了字符串内部表示的这种变化,默认情况下,字符全部落在ISO-8859-1范围内的字符串在内部用ISO-8859-1表示,而字符串用at表示.该范围之外的至少一个字符在内部以UTF-16表示,如前所述.确实,getBytes(StandardCharsets.UTF_16)不再返回内部表示.