String 是 Java 中很重要的一个数据类型,除了基本数据类型以外,String 是被使用的最广泛的了,但是,关于 String,其实还是有很多东西容易被忽略的。
就如本文我们要讨论的问题:Java 中的 String 有没有长度限制?
这个问题要分两个阶段看,分别是编译期和运行期。不同的时期限制不一样。
01 编译期
首先,我们先来合理的推断一下,当我们在代码中使用 String s = ""; 的形式来定义 String 对象的时候,"" 中字符的个数有没有限制呢?
既然是合理的推断,那就要要足够的依据,所以我们可以从 String 的源码入手,根据 public String(char value[], int offset, int count) 的定义,count 是 int 类型的,所以,char value[] 中最多可以保存 Integer.MAX_VALUE 个, 即 2147483647 字符。(jdk1.8.0_73)
但是,实验证明,String s = ""; 中,最多可以有 65534 个字符。如果超过这个个数。就会在编译期报错。
public static void main(String[] args) {
String s = "a...a";
System.out.println(s.length());
String s1 = "a...a";
System.out.println(s1.length());
}
以上代码,会在 String s1 = "a...a";// 共 65535 个 a 处编译失败:
✗ javac StringLenghDemo.java
StringLenghDemo.java:11: 错误: 常量字符串过长
明明说好的长度限制是 2147483647,为什么 65535 个字符就无法编译了呢?
当我们使用字符串字面量直接定义 String 的时候,是会把字符串在常量池中存储一份的。那么上面提到的 65534 其实是常量池的限制。
常量池中的每一种数据项也有自己的类型。Java 中的 UTF-8 编码的 Unicode 字符串在常量池中以 CONSTANT_Utf8 类型表示。
CONSTANTUtf8info 是一个 CONSTANTUtf8 类型的常量池数据项,它存储的是一个常量字符串。常量池中的所有字面量几乎都是通过 CONSTANTUtf8info 描述的。CONSTANTUtf8_info 的定义如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
由于本文的重点并不是 CONSTANTUtf8info 的介绍,这里就不详细展开了,我们只需要我们使用字面量定义的字符串在 class 文件中,是使用 CONSTANTUtf8info 存储的,而 CONSTANTUtf8info 中有 u2 length; 表明了该类型存储数据的长度。
u2 是无符号的 16 位整数,因此理论上允许的的最大长度是 2^16=65536。而 java class 文件是使用一种变体 UTF-8 格式来存放字符的,null 值使用两个 字节来表示,因此只剩下 65536- 2 = 65534 个字节。
关于这一点,在 the class file format spec 中也有明确说明:
The length of field and method names, field and method descriptors, and other constant string values is limited to 65535 characters by the 16-bit unsigned length item of the CONSTANTUtf8info structure (§4.4.7). Note that the limit is on the number of bytes in the encoding and not on the number of encoded characters. UTF-8 encodes some characters using two or three bytes. Thus, strings incorporating multibyte characters are further constrained.
也就是说,在 Java 中,所有需要保存在常量池中的数据,长度最大不能超过 65535,这当然也包括字符串的定义咯。
02 运行期
上面提到的这种 String 长度的限制是编译期的限制,也就是使用 String s= ""; 这种字面值方式定义的时候才会有的限制。
那么。String 在运行期有没有限制呢,答案是有的,就是我们前文提到的那个 Integer.MAX_VALUE ,这个值约等于 4G,在运行期,如果 String 的长度超过这个范围,就可能会抛出异常。(在 jdk 1.9 之前)
int 是一个 32 位变量类型,取正数部分来算的话,他们最长可以有
2^31-1 =2147483647 个 16-bit Unicodecharacter
2147483647 * 16 = 34359738352 位
34359738352 / 8 = 4294967294 (Byte)
4294967294 / 1024 = 4194303.998046875 (KB)
4194303.998046875 / 1024 = 4095.9999980926513671875 (MB)
4095.9999980926513671875 / 1024 = 3.99999999813735485076904296875 (GB)
觉得不错的话就点个好看再走呗~
“不积跬步,无以至千里”,希望未来的你能:有梦为马 随处可栖!加油,少年!
关注公众号:「Java 知己」,每天更新Java知识哦,期待你的到来!
发送「Group」,与 10 万程序员一起进步。
发送「面试」,领取BATJ面试资料、面试视频攻略。
发送「玩转算法」,领取《玩转算法》系列视频教程。
千万不要发送「1024」...