最近在与其他系统对接过程中,由于一些外部系统原因(网关不支持流传输),文件都走base64传输,给测试接口功能带来一些麻烦。由于待测试接口都与微服务形式暴露。就选择了常用的Junit单元测试。但整串base64拷入写好的测试用例中,在编译期就无法通过,无奈只能借助外部工程走流的形式rpc调用待测试功能。

Java中的String带来了长度限制。翻了一下String源码,从某个构造函数可以看出String内部字符数组支持的字符数量count的int类型。int类型在Java中包装类Integer提供了最大长度Integer.MAX_VALUE值为2^31-1也就是2147483647个字符。

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

但通过测试证明编译器根本存不了这么多字符串。于是翻了翻网上资料,发现String的长度限制分为两种,编译器限制和运行期限制。

编译器限制

String base64File = "...........";

通过上面代码运行测试用例发现有时候能走,有时候编译不过。
通过网上一个测试例子发现编译器最多能存储65534个字符多了就报错。

String s = "a...a";// 共65534个a
System.out.println(s.length());

String s1 = "a...a";// 共65535个a,编译失败
System.out.println(s1.length());
Error:(16, 21) java: 常量字符串过长

String中intern()使用这篇文章中有说过运行时常量池中的字符串常量有一部分来自于class文件加载一部分来自于运行时产生。

class文件中有一部分的内存称为常量池结构,它在class文件结构中排在class文件的主次版本号之后。主要存储两大类常量,分别是字面量和符号引用。常量池中的每一个常量都是一个表,对应不同的表结构。其中一项类型就是CONSTANT_Utf8_info对应的描述是UTF-8编码的字符串

CONSTANT_Utf8_info型常量的结构如下:

类型 名称 数量
u1 tag 1
u2 length 1
u1 bytes length

其中的length表明了UTF-8编码的字符串长度是多少字节。所以length表示字符串的存储长度。而u2是无符号的16位整数,能表达的最大值为65535。如果程序中定义的变量或方法名超过这个限制则编译无法通过。

由于UTF8编码中保留了ASCII编码,所以上面的例子可以声明65534个a,无法声明65535个a,如果使用汉字则能存储的更少。

运行期限制

通过编译对string限制来满足class文件中常量池的要求。但在运行期则没有class文件结构的限制。但依然有长度限制,即Integer.MAX_VALUE(2147483647),如果运行期生成的字符串超过这个范围会抛出异常。

Java中char类型占2个字节(16位),所以2147483647个字符的大小为2147483647 * 16 = 34359738352 位

34359738352 / 8 / 1024 / 1024 / 1024 = 3.99999999813735485076904296875G

运行期存进行换算的话最大大约可以存储4G。

参考

最后修改日期: 2019年9月15日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。