面试题01-String是否有长度限制
1、场景模拟
自己模拟20万长度的字符,赋值给String报错
检测字符串长度工具(http://tool.huixiang360.com/str/length.php)
2、原因分析
1、通过源码分析String应该是由char类型的数组构成
2、如果是char类型的数组那么没有其它限制的情况下String的长度应该为value字符串数组的长度
3、value字符串数组的长度为int类型,那么根据int类型的包装类Integer可以得到如下信息,最大值为2^31-1 但是根据场景模拟结果,显然长度根本没有到2^31-1 就报错了!!!
4、这个时候就必须推出JVM,JVM编译时会将字符串转换为字面量,在编译时将字面量放入常量池中,这时候JVM对字符串会做一些限制
参考Java虚拟机规则https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10
所有的常量池的通用规则如下
字符串的规则如下(这里定义的 u2 string_index 表示的是常量池的有效索引,其类型是CONSTANT_Utf8_info 结构体表示的)
那么什么是CONSTANT_Utf8_info规则
在class文件中u2表示的是无符号数占2个字节单位,我们知道1个字节占8位,2个字节就是16位 ,那么2个字节能表示的范围就是2^16- 1 = 65535(定义一组私有数据类型来表示 Class 文件的内容,它们包括 u1,u2 和 u4,分别代表了1、2 和 4 个字节的无符号数 每个 Class 文件都是由 8 字节为单位的字节流组成,所有的 16 位、32 位和 64 位长度的数 据将被构造成 2 个、4 个和 8 个 8 字节单位来表示)
5、综上可以确定字符串的长度是2^16-1了吗?不不不
根据官方解释,就是说数组的有效范围是【0-65535】,但是虚拟机还需要一个字节的指令作为结束符,所有真正有效范围是【0-65534】
注意点:这里的范围仅限编译时期,如果你是运行时拼接的字符串是可以超出这个范围的
// 也就是说如下情况,编译不报错,运行时拼接字符串是可以超过这个范围
public class StringTest {
public static void main(String[] args) {
String result = "";
for (int i = 0; i <1000_0000_00 ; i++) {
result+=i;
}
}
}
3、测试
准备字符为65534的字符串,验证通过
4、结论
通过对字符串的源码分析可知,字符串由字符数据char[ ]构成,由于数组的长度为int类型,而int的包装类是Integer,那么Integer最大的表示值应该为2^31-1, 但是通过翻阅java虚拟机手册可知,class文件格式的定义以及常量池中对String类型的结构体定义我们可以知道对于索引定义了u2,就是无符号占2个字节,2个字节可以表示的最大范围是2^16 -1 = 65535,但虚拟机需要最后一位为结束指令,所以这个范围就是65534。