【问题标题】:Java internal String representation: is it UTF-16?Java 内部字符串表示:是 UTF-16 吗?
【发布时间】:2015-03-02 11:03:42
【问题描述】:

我在 SO 上发现,Java 字符串在内部表示为 UTF-16。出于好奇,我开发并运行了 sn-p (Java 7):

public class StringExperiment {
    public static void main(String...args) throws UnsupportedEncodingException {
        System.out.println(Arrays.toString("ABC".getBytes()));
    }
}

导致:

[65, 66, 67]

正在打印到控制台输出。

它如何与 UTF-16 匹配?

更新。有没有办法编写一个程序来打印字符串的内部字节按原样

【问题讨论】:

标签: java string utf-8


【解决方案1】:

Java 的内部字符串表示基于它们的char,因此是 UTF-16。
Unless it isn't:现代 VM(自 Java 6 Update 21 Performance Release 起)可能会尝试通过使用基本 ASCII(单字节编码)就足够了。

序列化/java-native-interface 以modified CESU-8(UTF-8 的代理不可知变体)编码完成,NUL 表示为两个字节以避免嵌入零。

所有这些都与您的“测试”无关:
You are asking Java to encode the string in the platform's default-charset,这不是内部字符集:

public byte[] getBytes()

使用平台的默认字符集将此字符串编码为字节序列,并将结果存储到新的字节数组中。
当此字符串无法以默认字符集编码时,此方法的行为未指定。当需要对编码过程进行更多控制时,应使用 CharsetEncoder 类。

【讨论】:

  • 嗯,我不知道存在这样的选项;它可能会对性能产生相当不利的影响......
  • @fge: 是的,就像使用 UTF-16 而不是 UTF-8 处理字符串一样...尽管他们大概测试并发现它至少对 一些来说是值得优化的> Oracle 的工作负载。
  • 嗯,问题是当 Java 出现时,Unicode 只有 BMP,所以他们选择使用无符号 16 位字符作为存储字符的通用方式 :) 但是从那以后,当然,事情发生了变化...老实说,在内部存储为 UTF-8 性能会更差。
  • @fge:当然,但这只是因为他们注定要拥有 UTF-16 代码点随机访问,由于那段历史。
  • 另见stackoverflow.com/questions/8833385/… re: -XX:+UseCompressedStrings 选项的来来去去
【解决方案2】:

你好像误会了什么。

对于所有系统的关心,而且,大多数时候,开发人员关心的是,chars 也可以是信鸽,而Strings 是上述信鸽的序列。虽然是的,但在内部,字符串是 chars 的序列(更准确地说是 UTF-16 代码单元),但这不是这里的问题。

您不会将chars 写入文件,也不会从文件中读取chars。你写和读字节。

为了将字节序列读取为字符序列/信鸽序列,您需要一个解码器;同样(这就是您在这里所做的),为了将字符/信鸽转换为字节,您需要一个 编码器。在 Java 中,这两个都可以从Charset 获得。

String.getBytes() 恰好使用了具有默认平台字符编码的编码器(使用 Charset.defaultCharset() 获得),并且对于您的输入字符串 "ABC" 和您的 JRE 实现,生成的字节序列是 65, 66, 67. 因此结果。

现在,试试String.getBytes(Charset.forName("UTF-32LE")),你会得到不同的结果。

【讨论】:

    【解决方案3】:

    Java 字符串在内部确实表示为 UTF-16,但您正在调用 getBytes 方法,该方法执行 following(我的重点)

    public byte[] getBytes()
    

    将此字符串编码为字节序列使用平台的 默认字符集,将结果存储到一个新的字节数组中。

    而且您平台的默认编码可能不是 UTF-16。

    如果您使用允许您指定编码的变体,您可以看到字符串在其他编码中的外观:

    public byte[] getBytes(Charset charset)
    

    如果您查看source code 中的java.lang.String,您可以看到字符串在内部存储为(16 位)字符数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-30
      • 2016-05-04
      • 2016-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多