【问题标题】:Bytes of a string in JavaJava中字符串的字节数
【发布时间】:2011-05-22 02:24:45
【问题描述】:

在 Java 中,如果我有一个字符串 x,我如何计算该字符串中的字节数?

【问题讨论】:

  • 人们可能希望使用字符串来表示 HTTP 响应的主体,并使用大小来设置“Content-Length”标头,该标头以八位字节/字节而不是字符指定。 w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
  • 数据库列可能有字节长度限制,例如Oracle 中的 VARCHAR2(4000 字节)。人们可能想知道所需编码中字符串的字节数,以了解该字符串是否适合。
  • @iX3 和我尝试做的完全一样。
  • 我相信这个问题有两种可能的解释,取决于意图:一种是“我的字符串使用了多少内存?”。答案由下面的@roozbeh 提供(可能是模数 VM 微妙之处,如压缩的 OOPS)。另一个是,“如果我将字符串转换为 byte[],该字节数组将使用多少内存?”。这是 Andrzej Doyle 回答的问题。差异可能很大:UTF8 中的“Hello World”是 11 个字节,但字符串(每个 @roozbeh)是 50 个字节(如果我的数学是正确的)。
  • 我应该补充一点,这 11 个字节不包括保存它们的 byte[] 对象的开销,所以比较有点误导。

标签: java string


【解决方案1】:

字符串是字符(即代码点)的列表。用于表示字符串的字节数完全取决于您使用哪种编码将其转换为字节

也就是说,你可以把字符串转成字节数组,然后看它的大小如下:

// The input string for this test
final String string = "Hello World";

// Check length, in characters
System.out.println(string.length()); // prints "11"

// Check encoded sizes
final byte[] utf8Bytes = string.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "11"

final byte[] utf16Bytes= string.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "24"

final byte[] utf32Bytes = string.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "44"

final byte[] isoBytes = string.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "11"

final byte[] winBytes = string.getBytes("CP1252");
System.out.println(winBytes.length); // prints "11"

所以你看,即使是一个简单的“ASCII”字符串在其表示中也可以有不同数量的字节,这取决于所使用的编码。使用您对案例感兴趣的任何字符集作为getBytes() 的参数。并且不要陷入假设 UTF-8 将 每个 字符表示为单个字节的陷阱,因为这也不正确:

final String interesting = "\uF93D\uF936\uF949\uF942"; // Chinese ideograms

// Check length, in characters
System.out.println(interesting.length()); // prints "4"

// Check encoded sizes
final byte[] utf8Bytes = interesting.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "12"

final byte[] utf16Bytes= interesting.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "10"

final byte[] utf32Bytes = interesting.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "16"

final byte[] isoBytes = interesting.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "4" (probably encoded "????")

final byte[] winBytes = interesting.getBytes("CP1252");
System.out.println(winBytes.length); // prints "4" (probably encoded "????")

(请注意,如果您不提供字符集参数,则会使用平台的默认字符集。这在某些情况下可能很有用,但通常您应该避免依赖默认值,并且在需要编码/解码时始终使用显式字符集。)

【讨论】:

  • 如果我再次使用 getBytes()。它会给我与 x.length 相同的长度我错了,因为我不确定
  • @Green Ash 字节数组的长度 -- getBytes() -- 和 x.length 可以相等,但不保证相等。如果所有字符均由单个字节表示,则它将是相等的。对于每个字符使用一个字节(或更少)的字符编码(例如 ISO-8859-1),这始终适用。 UTF-8 使用 1 或 2 个字节,因此它取决于字符串中的确切字符。还有一些字符编码总是每个字符使用两个字节。
  • 我喜欢你的回答 :) ,所以它们可能在某种程度上是相同的,但我并不总是对的吗?好的。那么是否可以使用不带参数的方法,因为它会导致我出错!
  • @Green 重点是 bytes 的数量并不总是与 characters 的数量相同。 字节数 取决于所使用的字符编码。您必须知道您将使用哪种字符编码并将其考虑在内。你遇到了什么错误?如果您只使用getBytes(),它将使用您系统的默认字符编码。
  • @KorayTugay 是的,或多或少。不过,你可以争论因果的顺序。我更倾向于声明 char 始终为 2 个字节,因为它是一个原始数据类型 defined 为 2 个字节宽。 (而 UTF-16 表示主要是由此产生的结果,而不是反过来。)
【解决方案2】:

如果您使用 64 位引用运行:

sizeof(string) = 
8 + // object header used by the VM
8 + // 64-bit reference to char array (value)
8 + string.length() * 2 + // character array itself (object header + 16-bit chars)
4 + // offset integer
4 + // count integer
4 + // cached hash code

换句话说:

sizeof(string) = 36 + string.length() * 2

在 32 位 VM 或具有压缩 OOP (-XX:+UseCompressedOops) 的 64 位 VM 上,引用为 4 个字节。所以总数是:

sizeof(string) = 32 + string.length() * 2

这不考虑对字符串对象的引用。

【讨论】:

  • 我假设问题是关于在内存中为 String 对象分配的字节数。如果问题是关于序列化字符串所需的字节数,正如其他人指出的那样,这取决于所使用的编码。
  • 您的答案来源?谢谢
  • 注意:sizeof 应该是 8 的倍数。
【解决方案3】:

迂腐的答案(虽然不一定是最有用的答案,取决于你想对结果做什么)是:

string.length() * 2

Java 字符串物理存储在 UTF-16BE 编码中,每个代码单元使用 2 个字节,String.length() 以 UTF-16 代码单元测量长度,所以这相当于:

final byte[] utf16Bytes= string.getBytes("UTF-16BE");
System.out.println(utf16Bytes.length);

这将告诉您内部char 数组的大小,以字节为单位。

注意:"UTF-16" 将给出与 "UTF-16BE" 不同的结果,因为前一种编码将插入一个 BOM,将数组长度增加 2 个字节。

【讨论】:

【解决方案4】:

根据How to convert Strings to and from UTF8 byte arrays in Java

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);

【讨论】:

  • 但是对不起,当我编译你的代码时它给了我一个错误;因为参数 "UTF-8".where 当我传递一个空参数时,它给我的长度与 x.length 相同。我误解了这个概念。请帮忙
  • @Green Ash,你有什么版本的 Java?
  • @Green Ash,你遇到了什么异常?
  • 要清楚这是输出:test.java:11: unreported exception java.io.UnsupportedEncodingException;必须被捕获或声明被抛出 byte[] b = s.getBytes("UTF-8"); ^ 1 个错误 处理完成。
  • @Green,试试看:s.getBytes(Charset.forName("UTF-8"))
【解决方案5】:

String 实例在内存中分配一定数量的字节。也许您正在查看类似 sizeof("Hello World") 的东西,它会返回数据结构本身分配的字节数?

在Java 中,通常不需要sizeof 函数,因为我们从不分配内存来存储数据结构。我们可以查看String.java 文件进行粗略估计,我们会看到一些'int'、一些参考和char[]Java language specification 定义了 char 的范围从 0 到 65535,因此两个字节足以在内存中保留一个字符。但是 JVM 不必在 2 个字节中存储一个字符,它只需要保证 char 的实现可以保存定义范围的值。

所以sizeof 在 Java 中真的没有任何意义。但是,假设我们有一个很大的 String 并且一个 char 分配了两个字节,那么 String 对象的内存占用至少是 2 * str.length() 以字节为单位。

【讨论】:

    【解决方案6】:

    有一个方法叫做getBytes()。明智地使用它。

    【讨论】:

    • 明智 = 不要使用没有字符集参数的那个。
    • 为什么?如果我将环境配置为使用 UTF8 编码运行,这是一个问题吗?
    • getBytes 也会创建和复制字节数组,所以如果你说的是长字符串,这个操作可能会很昂贵。
    • @ticktock,如果你还在,是的,但还有什么选择?我来到这里是希望一个库函数能够返回所需的存储空间,这样我就可以将它组合成一个更大的分配。
    【解决方案7】:

    试试这个:

    Bytes.toBytes(x).length
    

    假设你之前声明并初始化了 x

    【讨论】:

    • 这是标准 Java 库的一部分吗?我找不到 Bytes 类。
    【解决方案8】:

    为避免 try catch,请使用:

    String s = "some text here";
    byte[] b = s.getBytes(StandardCharsets.UTF_8);
    System.out.println(b.length);
    

    【讨论】:

      【解决方案9】:

      apache commons试试这个:

      String src = "Hello"; //This will work with any serialisable object
      System.out.println(
                  "Object Size:" + SerializationUtils.serialize((Serializable) src).length)
      

      【讨论】:

        猜你喜欢
        • 2016-02-13
        • 2014-02-12
        • 2011-10-04
        • 2011-09-24
        • 2017-04-22
        • 2013-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多