When asking android Java-related questions, always mention that as there are some major differences.
The android ART runtime optimizes java.lang.String by compressing the normally two-byte Java chars into single-byte ASCII strings when possible. You can see it in the source of 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 is specified in the native code as:
// String Compression
static constexpr bool kUseStringCompression = true;
enum class StringCompressionFlag : uint32_t {
kCompressed = 0u,
kUncompressed = 1u
};
This flag is OR-ed with the count value:
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;
}
When loading strings from the constant pool, however, string compression is not performed. Hence you get a doubling of the original char count + 1 (333 = 166 * 2 + 1). That additional 1 is the "uncompressed" flag.
countfield doesn't exist in Java 11 (or at least I can't find it).