最近做项目遇到一个问题,服务商给我们传递数据的时候会将参数信息加密,奇怪的是我代码解密可以通过,因为测试解密方法,我手动解析的一下参数(因为等解码完成,我服务端的程序已经判断超时了,所以为了看返回的数据手动调的),结果提示常量字符串过长,那么String有没有长度限制的问题。
猜测:因为运行的时候可以通过,而手动编译的时候确提示常量字符串过长,所以运行是字符串长度是不是没有限制,而编译的时候会有限制呢???
我们先看下字符串的源码有没有定义字符串的长度。
可以看到String类中有很多重载的构造函数。
找找看有可以支持用户传入长度的方法。
长度是int那么他的长度是否就是int max=2147483647;
验证猜想:
运行的时候长度一万十万的都打印出来了,一百万的没有打印出来虽然但是猜测是内存溢出了,毕竟这么拼接字符串(内存溢出只是猜测没有验证)
长度一万正常但是长度为十万时!!!!
看来我的猜测是对的,运行的时候就算字符串长度超过十万也能运行,但是当字符串长度等于十万时就会报常量字符串过长,而且字符串长度可以传int的,为什么才十万就报错了???
Javac再编译时String s = "xxx";定义String的时候,xxx被我们称之为字面量,这种字面量在编译之后会以常量的形式进入到Class常量池。
String内部是以百char数组的形式存储,数组的长度是int类型,那么String允许的最大长度就是Integer.MAX_VALUE了。又由于java中的字符是以16位存储的,因此大概需要4GB的内存才能存储最大长度的字符串度。专不过这仅仅是对字符串变量而言,如果是字符串字面量(string literals),如“abc"、"1a2b"之类写在代码中的字符串literals,那么允许的最属大长度取决于字符串在常量池中的存储大小,也就是字符串在class格式文件中的存储格式:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
u2是无符号的16位整数,因此理论上允许的string literal的最大长度是2^16-1=65535。然而实际测试表明,允许的最大长度仅为65534,超过就编译错误了,这里在javac的代码中有定义代码中可以看出,当参数类型为String,并且长度大于等于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;
}
}
而要测试运行时,String的长度大小能否超过4G可以通过base64加密文件试试。
总结:String的长度是有限制的编译时长度在常量池中定义(String str = "ii"会编译成常量),运行时长度可以达到int的最大值,大概4G左右。路过的大佬有看到错误希望给小弟指出,感激不尽。