Java字符串字面量最大长度为何是65534而非65535?
问题背景
使用javac 21.0.1编译字符串字面量时,将'A'重复65534次可正常编译,但重复65535次会触发编译错误constant string too long。结合JVM规范与javac源码,原因可从两方面解释:
1. JVM规范的字节数限制
JVM类文件格式中,字符串字面量存储在CONSTANT_Utf8_info结构中:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}length表示字节数组的长度(而非最终字符串的字符数)
其中u2类型的最大值为0xFFFF,即65535——这是字节数的上限,而非字符数。对于单字节字符(如ASCII的'A'),字符数与字节数相等,理论上可存储65535个这类字符。
2. Javac的实现逻辑问题
查看javac源码中的checkStringConstant方法:
private void checkStringConstant(DiagnosticPosition pos, Object constValue) { if (nerrs != 0 || // only complain about a long string once constValue == null || !(constValue instanceof String str) || str.length() < PoolWriter.MAX_STRING_LENGTH) return; log.error(pos, Errors.LimitString); nerrs++; }
这里的判断逻辑是:当字符串字符数小于PoolWriter.MAX_STRING_LENGTH时不触发错误。假设PoolWriter.MAX_STRING_LENGTH的值为65535,那么当字符数等于65535时,就会触发错误——这直接导致65535个'A'编译失败的现象。
按照JVM规范,65535个单字节字符的UTF-8字节数刚好是65535,符合CONSTANT_Utf8_info的要求,因此正确的判断逻辑应为str.length() <= PoolWriter.MAX_STRING_LENGTH(前提是该常量对应字节数上限的字符数阈值)。
Javac用字符数做检查是一种简化方案:由于多字节字符(如中文)的字节数远大于字符数,设置65534的字符数阈值可确保字节数不超过65535,但这属于过度限制——因为65535个单字节字符的字节数刚好符合规范上限。
内容的提问来源于stack exchange,提问作者YujiSoftware

