java.lang.String: length() vs. count?

8

我有一个测试字符串:

String test = "oiwfoilfhlshflkshdlkfhsdlfhlskdhfslkhvslkvhvkjdhfkljshvdfkjhvdsköljhvskljdfhvblskjbkvljslkhjjssdlkhdsflksjflkjdlfjslkjljlfjslfjldfjjhvbksdjhbvslkdfjhbvslkjvhbslkvbjbn";

在调试期间,我注意到以下情况。当我打印出长度时:

System.out.println("Test length() : " + test.length());

返回

测试 length() : 166

当我进行调试时,我可以看到变量的 count 值为333。

enter image description here

count 表示什么意思?


5
请说明您使用的Java版本,因为在Java 11中count字段不存在(或者至少我找不到)。 - Slaw
2个回答

5

字符串实现包含字符数组 - 。因此,在某些实现中,计数字段用于计算数组的声明大小。

有人可能会注意到提供的计数值与给定的字符串长度相差两倍 - 这似乎是对ASCII / UTF-8 / UTF-16分歧的提示,因为在字符串实例中,1个Unicode(UTF-16)符号由2个字节表示。

一个例子:

String str = "f";
str.length(); // 1
str.getBytes().length; // 1

但是
String str = "ў";
str.length(); // 1
str.getBytes().length; // 2

参见:

您正在使用哪个JDK?这可能会更清楚地说明您的计数究竟是什么。


@EugenCovaci 的 shadow 与 Dalvik 的 GC 有关。 - Anton Hlinisty
很可能count也是这样,这就是我的观点。当声明String test =“bla bla”时,带有计数参数的构造函数不会被调用 - user10639668
1
我认为count表示字符串的原始字节保留(每个字符2个字节),然后再加上一个终止符。然而:Java会立即将传统的ASCII字符降至一个字节,以进行优化。请参见Anto Hlinisty使用getBytes().length进行的实验。 - Daniel Schmidt
5
等等,所以你只是发现一个方法参数与一个未知JRE中的私有字段同名,并将它们声明为相同的内容?而且作为参考,你提供了一个完全不同含义的旧JDK实现的私有字段?(请注意,你提供链接的那个实现有public int length(){return count;},因此它不会显示问题中的任何行为)。这个帖子怎么获得了这么多赞? - Ordous
2
(UTF-16)符号由2个字符表示:Java中的char,Character和String元素确实是1个UTF-16代码单元,占用2个字节。说chars会引起混淆。 - Tom Blodget
显示剩余4条评论

3
当询问与Java相关的问题时,请始终提及它,因为存在一些重大差异。
Android ART运行时通过在可能的情况下将通常为两个字节的Java字符压缩为单字节ASCII字符串来优化java.lang.String。您可以在java.lang.String的源代码中看到它:
public int length() {
    // BEGIN Android-changed: Get length from count field rather than value array (see above).
    // return value.length;
    final boolean STRING_COMPRESSION_ENABLED = true;
    if (STRING_COMPRESSION_ENABLED) {
        // For the compression purposes (save the characters as 8-bit if all characters
        // are ASCII), the least significant bit of "count" is used as the compression flag.
        return (count >>> 1);
    } else {
        return count;
    }
}

字符串压缩在原生代码中的规定为:如下
// String Compression
static constexpr bool kUseStringCompression = true;
enum class StringCompressionFlag : uint32_t {
    kCompressed = 0u,
    kUncompressed = 1u
};

此标记与count值进行逻辑或运算:OR-ed
static int32_t GetFlaggedCount(int32_t length, bool compressible) {
    return kUseStringCompression
        ? static_cast<int32_t>((static_cast<uint32_t>(length) << 1) |
                               (static_cast<uint32_t>(compressible
                                                          ? StringCompressionFlag::kCompressed
                                                          : StringCompressionFlag::kUncompressed)))
        : length;
}

然而,从常量池加载字符串时,并不执行字符串压缩。因此,您将获得原始字符数的加倍+1(333 = 166 * 2 + 1)。该附加的1是“未压缩”标志。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接