最近做項目遇到一個問題,服務商給我們傳遞數據的時候會將參數信息加密,奇怪的是我代碼解密可以通過,因為測試解密方法,我手動解析的一下參數(因為等解碼完成,我服務端的程序已經判斷超時了,所以為了看返回的數據手動調的),結果提示常量字符串過長,那么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左右。路過的大佬有看到錯誤希望給小弟指出,感激不盡。