在看过字节码后,理解这部分的原理就简单多了。

编译期

假设写了这样的代码

  1. public static void main(String[] args) {
  2. String s = "a...a";// 共65534个a
  3. System.out.println(s.length());
  4. String s1 = "a...a";// 共65535个a
  5. System.out.println(s1.length());
  6. }

编译期的时候会生成字节码,所以字符串会被存储在字节码的常量池中,而常量池表示字符串的是通过 CONSTANTUtf8info 描述的

  1. CONSTANT_Utf8_info {
  2. u1 tag;
  3. u2 length;
  4. u1 bytes[length];
  5. }

可以看到 length 的类型为U2,u2代表两个字节,u2是无符号的16位整数,因此理论上允许的的最大长度是2^16=65536。而 java class 文件是使用一种变体UTF-8格式来存放字符的,null 值使用两个 字节来表示,因此只剩下 65536- 2 = 65534个字节

运行期

在 String 类中,是使用一个字符数组来维护字符序列的,其声明如下:

  1. private final char value[];

这也就是说,String 的最大长度取决于字符数组的最大长度,我们知道,在指定数组长度的时候,可以使用 byte、short、char、int 类型,而不能够使用 long 类型。这也就是说,数组的最大长度就是 int 类型的最大值,即 0x7fffffff,十进制就是 2147483647,同理,这也就是 String 所能容纳的最大字符数量。

  1. 2^31-1 =2147483647 16-bit Unicodecharacter
  2. 2147483647 * 16 = 34359738352
  3. 34359738352 / 8 = 4294967294 (Byte)
  4. 4294967294 / 1024 = 4194303.998046875 (KB)
  5. 4194303.998046875 / 1024 = 4095.9999980926513671875 (MB)
  6. 4095.9999980926513671875 / 1024 = 3.99999999813735485076904296875 (GB)

大约 4个G