侧边栏壁纸
  • 累计撰写 93 篇文章
  • 累计创建 35 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

String 能存储多少个字符 ?

天明
2024-10-13 / 0 评论 / 0 点赞 / 3 阅读 / 3030 字 / 正在检测是否收录...

1、首先 String 的 length 方法返回是 int。所以理论上长度一定不会超过 int 的最大值。

2、编译器源码如下,限制了字符串长度大于等于 65535 就会编译不通过

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

Java 中的字符常量都是使用 UTF8 编码的,UTF8 编码使用 1~4 个字节来表示具体的 Unicode 字符。所以有的字符占用一个字节,而我们平时所用的大部分中文都需要 3 个字节来存储。

//65534个字母,编译通过
String s1 = "aa..a";

//21845个中文”文“,编译通过
String s2 = "文文...文";

//一个英文字母a加上21845个中文”文“,编译失败
String s3 = "a文文...文";


对于 s1,一个字母 d 的 UTF8 编码占用一个字节,65534 字母占用 65534 个字节,长度是 65534,长度和存储都没超过限制,所以可以编译通过。

对于 s2,一个中文占用 3 个字节,21845 个正好占用 65535 个字节,而且字符串长度是 21845,长度和存储也都没超过限制,所以可以编译通过。

对于 s3,一个英文字母 d 加上 21845 个中文” 自 “占用 65536 个字节,超过了存储最大限制,编译失败。

3、JVM 规范对常量池有所限制。量池中的每一种数据项都有自己的类型。Java 中的 UTF-8 编码的 Unicode 字符串在常量池中以 CONSTANTUtf8类型表示。CONSTANTUtf8的数据结构如下:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

我们重点关注下长度为 length 的那个 bytes 数组,这个数组就是真正存储常量数据的地方,而 length 就是数组可以存储的最大字节数。length 的类型是 u2,u2 是无符号的 16 位整数,因此理论上允许的的最大长度是 2^16-1=65535。所以上面 byte 数组的最大长度可以是 65535

4、运行时限制

String 运行时的限制主要体现在 String 的构造函数上。下面是 String 的一个构造函数:

public String(char value[], int offset, int count) {
    ...
}

上面的 count 值就是字符串的最大长度。在 Java 中,int 的最大长度是 2^31-1。所以在运行时,String 的最大长度是 2^31-1。

但是这个也是理论上的长度,实际的长度还要看你 JVM 的内存。我们来看下,最大的字符串会占用多大的内存。

(2^31-1)*16/8/1024/1024/1024 = 2GB

所以在最坏的情况下,一个最大的字符串要占用 2GB 的内存。如果你的虚拟机不能分配这么多内存的话,会直接报错的。

补充:JDK9 以后对 String 的存储进行了优化。底层不再使用 char 数组存储字符串,而是使用 byte 数组。对于 LATIN1 字符的字符串可以节省一倍的内存空间。

0

评论区