1、String类型最大能存多少字符

1.1、从String.class的定义来看
内部是用char[]数组实现的,char[]数组的长度用int定义,Integer.MAX_VALUE ,约为2G

1.1、运行时限制:String当临时变量使用时
在普通的代码调临时创建的String变量,存在java的堆中,String的长度理论上取决于传入的byte[]长度。
参考ArrayList数组分配置长度可知,有些虚拟机在数组中保留一些头词,数组的长度不能超过

Integer.MAX_VALUE - 8

尝试分配更大的数组可能会导致OOM,
即byte[]的最大长度不能超过

byte[] bytes = new byte[Integer.MAX_VALUE-8];

当然,当JVM的堆空间不足以分配时,也会抛出OOM异常。

1.2、编译期的限制:String变量是一个类中的全局变量时

private final static String LONG_STRING = "aaa";

这样定义的字符串在编译期就已经确定了,"aaa"字符串存放在方法区的常量池中,
代码编译成字节码以后,String的数据结构为CONSTANT_Utf8_info表示,即

CONSTANT_Utf8_info{
u1 tag;
u2 length;   // 0~65535
u1 bytes[length];
}

u2 length,表示byte数组的长度,u2无符号,表示2个字节16位,能表示的最大值为2^16-1=65535
因此,最多只能存放65535个字节长度的字符串

由Javac编译器的额外限制。在Javac的源代码中可以找到以下代码:

private void checkStringConstant(DiagnosticPosition var1, Object var2) {
    if (this.nerrs == 0 && var2 != null 
        && var2 instanceof String 
        && ((String)var2).length() >= 65535) {//对string长度的限制
        this.log.error(var1, "limit.string", new Object[0]);
        ++this.nerrs;
    }
}

代码中可以看出,当参数类型为String时,并且长度大于等于65535的时候,就会导致编译失败。
即String的字符长度(字符个数)要小于65535,字节数不能超过65535。
因此:
当字符串是一个字符占用一个字节时,如全英文时,一个字符占一个字节,可以存65534个字符。
当字符串是一个字符占用多个字节时,如全中文时,如果是utf-8编码,一个中文占3个字节,那和可存65533/3=21845个字符串。

结论:
编译期的限制:字符串的UTF8编码值的字节数不能超过65535,字符串的长度不能超过65534;
运行时限制:字符串的长度不能超过2^31-1,占用的内存数不能超过虚拟机能够提供的最大值。