IDEA編譯報(bào)錯(cuò)“java: 常量字符串過(guò)長(zhǎng)”的原因及解決方法
一、問(wèn)題描述
今天在開(kāi)發(fā)過(guò)程中,由于嘗試將一個(gè)文件的 Base64
字符串設(shè)置為常量,結(jié)果導(dǎo)致 IDEA 編譯的時(shí)候出現(xiàn)了如下報(bào)錯(cuò):
- java: 常量字符串過(guò)長(zhǎng)
二、問(wèn)題原因
2.1 理論角度
在 Java 中,常量字符串過(guò)長(zhǎng)的問(wèn)題通常是 由于編譯器對(duì)字符串常量的長(zhǎng)度有限制 導(dǎo)致的。
眾所周知,Java代碼是由 Java編譯器(javac)
編譯為 class
字節(jié)碼之后運(yùn)行的。這個(gè)報(bào)錯(cuò)就是因?yàn)?javac 對(duì)字符串常量有一個(gè)上線,通常是 65534 個(gè)字符串。這個(gè)限制是由于 Java 編譯器在處理字符串常量時(shí),使用了 16位
的無(wú)符號(hào)證書(shū)來(lái)表示字符串的長(zhǎng)度,因此最大值為 2^16 - 1 = 65535,但實(shí)際使用中會(huì)減去一個(gè)字符的空間用于其他用途,所以最大長(zhǎng)度為 65534。
在 IDEA 中編寫代碼時(shí),如果定義了一個(gè)超過(guò) 65534 個(gè)字符的字符串常量,編譯器就會(huì)報(bào)錯(cuò):java: 常量字符串過(guò)長(zhǎng)。
JVM 規(guī)范文檔: https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-4.html#jvms-4.4.3
查看 JVM 規(guī)范文檔可以看到:在 Java 中,常量 String 的結(jié)構(gòu)體如下:
其中 string_index
指針指向常量池的一個(gè)條目,這個(gè)條目的結(jié)構(gòu)體格式為 CONSTANT_Utf8_info
。這個(gè)結(jié)構(gòu)體的定義如下所示:
由上圖可知,一個(gè) String 類型的常量的最大長(zhǎng)度為 2^16 - 1 = 65535
,但實(shí)際使用中會(huì)減去一個(gè)字符的空間用于其他用途,所以最大長(zhǎng)度為 65534。
2.2 源碼角度
下面我們?cè)購(gòu)?javac 源碼角度進(jìn)行分析,源碼下載地址:https://jdk.java.net/java-se-ri/8-MR6。
在 \lib\src\jdk.compiler\com\sun\tools\javac\jvm|Gen.java
中可以看到如下代碼:
而這個(gè) PoolWriter.MAX_STRING_LENGTH
的值為:
從代碼可以看到,要求小于 2^16-1
,所以得出 javac 允許常量 String 保存的最大字節(jié)數(shù)為 0xFFF-1,即 2^16-1-1=65534
。
三、解決方案
解決方案①:StringBuilder 拼接
我們可以使用 StringBuilder
進(jìn)行字符串拼接的方式來(lái)解決這個(gè)問(wèn)題,只要每次拼接的長(zhǎng)度不超過(guò) 65534 即可。
public static String getConstant() { StringBuilder builder = new StringBuilder(); builder.append("字符串1"); builder.append("字符串2"); // ... return builder.toString(); }
解決方案②:讀取文件內(nèi)容
還有一種方式是將字符串寫入文件后讀出來(lái),如下所示:
try (BufferedReader reader = new BufferedReader(new FileReader("longString.txt"))) { StringBuilder builder = new StringBuilder(); String line; while ((line = reader.readLine() != null)) { builder.append(line); } String longString = builder.toString(); } catch (IOException e) { e.printStackTrace(); }
除了兩種方式,其余幾種方式小編親試均無(wú)效:
- 使用加號(hào)連接字符串
- 使用換行符
- 使用Eclipse編譯器
四、方案驗(yàn)證
我們先創(chuàng)建一個(gè) 65535 長(zhǎng)度的字符串試一下,結(jié)果如下所示,不出意外地報(bào)錯(cuò)了:
下面我們?nèi)サ粢粋€(gè)字符,長(zhǎng)度調(diào)整為 65534,再次執(zhí)行,就可以正常打印了,如下圖所示:
現(xiàn)在我們已經(jīng)確定當(dāng)長(zhǎng)度超過(guò) 65534 的時(shí)候就會(huì)報(bào)錯(cuò)了,那么我們將長(zhǎng)度改為 65535,然后使用 StringBuilder
來(lái)實(shí)現(xiàn),結(jié)果如下所示:
整理完畢。
到此這篇關(guān)于IDEA編譯報(bào)錯(cuò)“java: 常量字符串過(guò)長(zhǎng)”的原因及解決方法的文章就介紹到這了,更多相關(guān)java常量字符串過(guò)長(zhǎng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot基于docsify?實(shí)現(xiàn)隨身文檔
這篇文章主要介紹了springboot基于docsify實(shí)現(xiàn)隨身文檔的相關(guān)資料,需要的朋友可以參考下2022-09-09詳解Java中synchronized關(guān)鍵字的死鎖和內(nèi)存占用問(wèn)題
Java的synchronized關(guān)鍵字用來(lái)進(jìn)行線程同步操作,然而這在使用中經(jīng)常會(huì)遇到一些問(wèn)題,這里我們就來(lái)詳解Java中synchronized關(guān)鍵字的死鎖和內(nèi)存占用問(wèn)題:2016-06-06如何使用Java統(tǒng)計(jì)gitlab代碼行數(shù)
這篇文章主要介紹了如何使用Java統(tǒng)計(jì)gitlab代碼行數(shù),實(shí)現(xiàn)方式通過(guò)git腳本將所有的項(xiàng)目拉下來(lái)并然后通過(guò)進(jìn)行代碼行數(shù)的統(tǒng)計(jì),需要的朋友可以參考下2023-10-10IDEA調(diào)試源碼小技巧之辨別抽象類或接口多種實(shí)現(xiàn)類的正確路徑
這篇文章主要介紹了IDEA調(diào)試源碼小技巧之辨別抽象類或接口多種實(shí)現(xiàn)類的正確路徑,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01SpringBoot整合Swagger接口文檔工具的流程步驟
我們?cè)陂_(kāi)發(fā)接口的時(shí)候,會(huì)將接口文檔給前端的開(kāi)發(fā)者進(jìn)行對(duì)接,我們可以通過(guò)Postman或者Yapi等接口管理工具進(jìn)行編寫管理,實(shí)際開(kāi)發(fā)中,接口的管理確實(shí)也應(yīng)該通過(guò)專業(yè)的工具管理,本文,我們就來(lái)談?wù)勗趺丛赟pringBoot整合Swagger接口文檔工具2023-08-08