最近回顾了一下String的长度,记录一下, 万一下次忘了方便再次记忆!
Java中的String的长度要要分两个阶段去思考:
1、编译期:
在JDK1.8中,看过String的源码的应该知道,根据public String(char value[], int offset, int count)的定义,count是int类型的,所以,char value[]中最多可以保存Integer.MAX_VALUE个,即2147483647字符。
但是实际上却不一样,String s = “”;中,最多可以有65534个字符。如果超过这个个数。就会在编译期报错。
public static void main(String[] args) {
String s = "1....";// 共65534个1
System.out.println(s.length());
String s1 = "1...";// 共65535个1
System.out.println(s1.length());
}
当String在编译期的长度超过了65534就会报异常:
javac StringLenghDemo.java
StringLenghDemo.java:11: 错误: 常量字符串过长
这个是为什么了?
当我们使用字符串字面量直接定义String的时候,是会把字符串在常量池中存储一份的。那么上面提到的65534其实是常量池的限制。
在JVM中的常量池中的每一种数据项也有自己的类型。Java中的UTF-8编码的Unicode字符串在常量池中以CONSTANT_Utf8类型表示。
CONSTANTUtf8info是一个CONSTANTUtf8类型的常量池数据项,它存储的是一个常量字符串。常量池中的所有字面量几乎都是通过CONSTANTUtf8info描述的。CONSTANTUtf8_info的定义如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
我们使用字面量定义的字符串在class文件中,是使用CONSTANTUtf8info存储的,而CONSTANTUtf8info中有u2 length;表明了该类型存储数据的长度。
u2是无符号的16位整数,因此理论上允许的的最大长度是2^16=65536。而 java class 文件是使用一种变体UTF-8格式来存放字符的,null 值使用两个 字节来表示,因此只剩下 65536- 2 = 65534个字节。
在Java中,所有需要保存在常量池中的数据,长度最大不能超过65535,这当然也包括字符串的定义咯。
2、运行期:
上面讲的是String字符串在编译期的长度,而String在运行期的长度取决于它源码中的:
public String(char value[], int offset, int count)的定义,count是int类型的,所以,char value[]中最多可以保存Integer.MAX_VALUE个,即2147483647字符,这个值约等于4G,在运行期,如果String的长度超过这个范围,就可能会抛出异常。(在jdk 1.9之前)。
附上网上找的换算:
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)