String 最多能存储多少个字符/String 字符串的最大长度/String 字符串有没有长度限制

本文主要是介绍String 最多能存储多少个字符/String 字符串的最大长度/String 字符串有没有长度限制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1.编译时字节限制
  • 2.运行时长度限制
  • 3.小结
  • 4.补充

基于 JDK8 进行分析

1.编译时字节限制

String s = "11111...1111"; // 其中有 10 万个字符 "1"

当我们使用如上形式定义一个字符串的时候,当我们执行 javac 编译时,是会抛出异常的,提示 java: constant string too long

javac 是用于将 Java 源文件编译成 class 字节码二进制文件,那么在 class 文件生成过程中,就需要遵守一定的规范。

根据《Java 虚拟机规范》中对常量池的定义,CONSTANT_String_info 用于表示 java.lang.String 类型的常量对象,格式如下:

 CONSTANT_String_info {u1 tag;u2 string_index;
}

其中,string_index 项的值必须是对常量池的有效索引,常量池在该索引处的项必须是 CONSTANT_Utf8_info 结构,表示一组 Unicode 码点序列,这组 Unicode 码点序列最终会被初始化为一个 String 对象。

CONSTANT_Utf8_info 结构用于表示字符串常量的值:

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

其中,length 则指明了 bytes[] 数组的长度,其类型为 u2,即两个字节的无符号数,那么其可表示的最大值为 2 16 − 1 = 65535 2^{16} - 1 = 65535 2161=65535

也就是说,编译时生成的 class 文件中的字符串常量的字节数不能超过 65535。

但即使我们定义了一个由 65535 个 “1” 组成的字符串,还是会允许报错,报错原因还是 java: constant string too long

这个原因可以在 javactools.jar 包中找到,在 com.sun.tools.javac.jvm.Gen 类中有如下方法:

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

当参数类型为 String,并且长度大于等于 65535 的时候,就会导致编译失败。

为什么最大长度是 65534 而不是 65535 呢?这是 Java 虚拟机历史上的一个设计缺陷:如果 Java 虚拟机中的一个方法的 code 属性的长度刚好是 65535 个字节,并且以一个 1 个字节长度的指令结束,那么这条指令将不能被异常处理器所处理。不过编译器可以通过限制任何方法、实例初始化方法或类初始化方法的 code[] 数组最大长度为 65534,这样可以间接弥补这个 BUG。

所以,综合 CONSTANT_Utf8_info 中的 length 大小限制与 javac 检查机制,字符串常量的最大字节数为 65535,最大长度为 65534。

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

// 65534 个字母,编译通过
String s1 = "dd..d";// 21845 个中文 “自”,编译通过
String s2 = "自自...自";// 一个英文字母 d 加上 21845 个中文 “自”,编译失败
String s3 = "d自自...自";
  • 对于 s1,一个字母 d 的 UTF8 编码占用 1 个字节,65534 字母占用 65534 个字节,长度是 65534,字节数与长度都没有超出限制,所以可以编译通过。
  • 对于 s2,一个中文占用 3 个字节,21845 个正好占用 65535 个字节,而且字符串长度是 21845,字节数与长度都没有超出限制,所以可以编译通过。
  • 对于 s3,一个英文字母 d 加上 21845 个中文“自”占用 65536 个字节,超过了最大字节数,编译失败。

2.运行时长度限制

public int length() {return value.length;
}

String 类提供了一个 length() 方法,返回值为有符号的 32 位的 int 类型,所以理论上 String 的最大长度为 2 31 − 1 2^{31} -1 2311,因此在最大长度情况下占用内存约 ( 2 31 − 1 ) ∗ 2 ∗ 16 / 8 / 1024 / 1024 / 1024 = 4 G B (2^{31}-1)*2*16/8/1024/1024/1024 = 4GB (2311)216/8/1024/1024/1024=4GB​。如果 JVM 不能分配这么多内存的话,会出现 OOM 内存不足错误。

// success
public class Main {public static void main(String[] args) throws IOException {String s = "";for (int i = 0; i < 100000; i++) {s += "1";}// 100000System.out.println(s.length());System.out.println(s);}
}

3.小结

String 在不同的时期,具有不同的长度限制。

  • 编译时限制:UTF8 编码的字符串常量的最大字节数为 65535,最大长度为 65534
  • 运行时限制:字符串的长度不能超过 2 31 − 1 2^{31}-1 2311,且占用的内存不能超过当前虚拟机还能够提供的最大值。

4.补充

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

这篇关于String 最多能存储多少个字符/String 字符串的最大长度/String 字符串有没有长度限制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/945706

相关文章

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

poj 3723 kruscal,反边取最大生成树。

题意: 需要征募女兵N人,男兵M人。 每征募一个人需要花费10000美元,但是如果已经招募的人中有一些关系亲密的人,那么可以少花一些钱。 给出若干的男女之间的1~9999之间的亲密关系度,征募某个人的费用是10000 - (已经征募的人中和自己的亲密度的最大值)。 要求通过适当的招募顺序使得征募所有人的费用最小。 解析: 先设想无向图,在征募某个人a时,如果使用了a和b之间的关系

poj 3258 二分最小值最大

题意: 有一些石头排成一条线,第一个和最后一个不能去掉。 其余的共可以去掉m块,要使去掉后石头间距的最小值最大。 解析: 二分石头,最小值最大。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <c

poj 2175 最小费用最大流TLE

题意: 一条街上有n个大楼,坐标为xi,yi,bi个人在里面工作。 然后防空洞的坐标为pj,qj,可以容纳cj个人。 从大楼i中的人到防空洞j去避难所需的时间为 abs(xi - pi) + (yi - qi) + 1。 现在设计了一个避难计划,指定从大楼i到防空洞j避难的人数 eij。 判断如果按照原计划进行,所有人避难所用的时间总和是不是最小的。 若是,输出“OPETIMAL",若

poj 2135 有流量限制的最小费用最大流

题意: 农场里有n块地,其中约翰的家在1号地,二n号地有个很大的仓库。 农场有M条道路(双向),道路i连接着ai号地和bi号地,长度为ci。 约翰希望按照从家里出发,经过若干块地后到达仓库,然后再返回家中的顺序带朋友参观。 如果要求往返不能经过同一条路两次,求参观路线总长度的最小值。 解析: 如果只考虑去或者回的情况,问题只不过是无向图中两点之间的最短路问题。 但是现在要去要回

poj 2594 二分图最大独立集

题意: 求一张图的最大独立集,这题不同的地方在于,间接相邻的点也可以有一条边,所以用floyd来把间接相邻的边也连起来。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <sta

poj 3422 有流量限制的最小费用流 反用求最大 + 拆点

题意: 给一个n*n(50 * 50) 的数字迷宫,从左上点开始走,走到右下点。 每次只能往右移一格,或者往下移一格。 每个格子,第一次到达时可以获得格子对应的数字作为奖励,再次到达则没有奖励。 问走k次这个迷宫,最大能获得多少奖励。 解析: 拆点,拿样例来说明: 3 2 1 2 3 0 2 1 1 4 2 3*3的数字迷宫,走两次最大能获得多少奖励。 将每个点拆成两个

poj 2195 bfs+有流量限制的最小费用流

题意: 给一张n * m(100 * 100)的图,图中” . " 代表空地, “ M ” 代表人, “ H ” 代表家。 现在,要你安排每个人从他所在的地方移动到家里,每移动一格的消耗是1,求最小的消耗。 人可以移动到家的那一格但是不进去。 解析: 先用bfs搞出每个M与每个H的距离。 然后就是网络流的建图过程了,先抽象出源点s和汇点t。 令源点与每个人相连,容量为1,费用为

poj 3068 有流量限制的最小费用网络流

题意: m条有向边连接了n个仓库,每条边都有一定费用。 将两种危险品从0运到n-1,除了起点和终点外,危险品不能放在一起,也不能走相同的路径。 求最小的费用是多少。 解析: 抽象出一个源点s一个汇点t,源点与0相连,费用为0,容量为2。 汇点与n - 1相连,费用为0,容量为2。 每条边之间也相连,费用为每条边的费用,容量为1。 建图完毕之后,求一条流量为2的最小费用流就行了