String 类型的对象,他们是有长度限制的,String 对象并不能“存储”无限长度的字符串。关于 String 的长度限制要从编译时限制和运行时限制两方面考虑。
一、编译时限制:65534
我们知道字符串常量会被放入方法区的常量池中,JVM 规范对常量池有所限制。常量池中的每一种数据项都有自己的类型。Java 中的 UTF-8 编码的 Unicode 字符串在常量池中以 CONSTANT_Utf8
类型表示。
CONSTANT_Utf8的数据结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
我们重点关注下长度为 length 的那个 bytes 数组,这个数组就是真正存储常量数据的地方,而 length 就是数组可以存储的最大字节数。length 的类型是 u2,u2 是无符号的 16 位整数,因此理论上允许的的最大长度是 2^16-1=65535
。但是由于 JVM 需要 1 个字节表示结束指令,所以编译时 String 最大长度不能超过 65534。
二、运行时限制:2^31 -1
字符串的内容是由一个字符数组 char[] 来存储的,而数组的长度及索引都是 int 类型。在 Java 中,int 的最大长度是2^31 -1
。
但是这个也是理论上的长度,实际的长度还要看你 JVM 的内存。最大的字符串会占用多大的内存为 4GB。计算方式如下:
(2^31-1)*2*16/8/1024/1024/1024 = 4GB
所以在最坏的情况下,一个最大的字符串要占用 4GB 的内存。如果你的虚拟机不能分配这么多内存的话,会直接报错的。
JDK9 以后对 String 的存储进行了优化。底层不再使用 char 数组存储字符串,而是使用 byte 数组。对于 LATIN1 字符的字符串可以节省一倍的内存空间。