做项目,客户端这里自己模拟json数据时,一时没忍住搞得json字符串太长了(idea上大概有600多行吧),这个问题就蹦出来了。老方法直接google、百度然后看到一堆有关String 字符串常量池字符最大限制的文章,这些前辈都是从jvm的运行时常量池的常量表占的内存数,从原理上讲解了常量池所能容纳的最大字符数。对于不了解jvm的同学来说,啥无符号数、有符号数、u1、u2之类的看着看着就懵逼了。俗话说学而不思则罔,这里我就从常量池和内存区域的角度来简单分析下自己的观点。相对jvm的那套理论感觉更容易使人接受。

一、背景

/**
* Created by sunnyDay on 2019/11/19 17:31
* <p>
* double check
*/
public class Jsons {
private volatile static Jsons instance;

private Jsons() {
}
public static Jsons getInstance() {
if (instance == null) {
synchronized ("lock") {
if (instance == null) {
instance = new Jsons();
}
}
}
return instance;
}

public String getConstellationTestJson(){
return "很长的json,粘贴的下图json文件的字符串"
}
}

public class Test {
public static void main(String[] args) {
// 编译时直接报错
System.out.println(Jsons.getInstance().getConstellationTestJson());
}
}

如上:就是一个工具类,提供json字符串,为了演示我单独抽出来放idea中跑了下。

二、字符串String的最大长度
理论解析:
传送门

三、我的理解及其解决方案
理论性的东西前辈们都总结的差不多了,这里就添加下个人理解。及其解决方案。

1、首先理解下jvm方法区的运行时池
好处:
常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
注意点:
1、java中基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean。这里就就只说字符传常量池相关。
2、java中以双引号引住的内容就是字符创常量,编译时就会吧双引号引的内容放入字符创常量池。

2、字符创常量池的实战参考(一定要看)
String stra = "abcd"; // 对象存储在常量池中
String strb = new String("abcd");// new 就是在堆中分配了新的地址
System.out.println(stra==strb);//false

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2; //对于字符串变量的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,其属于在运行时创建的字符串,具有独立的内存地址,所以不引用自同一String对象。
System.out.println("string" == "str" + "ing");// true 只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入常量池中
System.out.println(str3 == str4);//false
String str5 = "string";
System.out.println(str3 == str5);//true

注意点:
1、+号连接的对象引用
2、+号链接的字符串常量

3、解决方案
不让放那么多,这里放不了我们不放这里或者这里放少点。不ojbk了。太聪明了嘿嘿嘿!!!

(1)错误解决方式

public String getConstellationTestJson(){
return "很长的json一半"+"很长的json一半";
}

这里+号拼接的结果还是会放进常量池的。参考实战。

(2)正确解决方式

```java
public String getConstellationTestJson(){
String s1 = "很长的json一半"; //内容放常量池
String s2 = "很长的json一半"; // 内容放常量池
return s1+s2; // 结果具有了新的内存地址(堆中)
}

解决,s1+s2的结果会放入新的内存地址中,参考上文实战。

(3)正确解决 使用new String 拆分拼接

(4)使用StringBuild#StringBuffer 拆分拼接

(5)通过文件读取(这里使用安卓的assets为例子)

private String getAssetsData() {
String result = "";
try {
InputStream mAssets = getAssets().open("dream.json");
int lenght = mAssets.available();
byte[] buffer = new byte[lenght];
mAssets.read(buffer);
mAssets.close();
result = new String(buffer, StandardCharsets.UTF_8); // 关键之处
return result;
} catch (IOException e) {
e.printStackTrace();
return result;
}
}

4、感悟
只要堆的内存不满,或者拆分的子字符串满足常量池大小,就基本没啥问题了。

5、推荐参考:java内存区域与内存溢出异常的常量池部分内容
————————————————
版权声明:本文为CSDN博主「dev晴天」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38350635/article/details/103495951

【转】Error,java对常量池来说字符串xxx的UTF8表示过长的解决及其理解的更多相关文章

  1. 【JVM】Java 8 中的常量池、字符串池、包装类对象池

    1 - 引言 2 - 常量池 2.1 你真的懂 Java的“字面量”和“常量”吗? 2.2 常量和静态/运行时常量池有什么关系?什么是常量池? 2.3 字节码下的常量池以及常量池的加载机制 2.4 是 ...

  2. Java字符串常量池及字符串判等解析

    一.理解"=="的含义 "=="常用于两个对象的判等操作,在Java中,"=="主要有以下两种用法: 1.基础数据类型:比较的是他们的值是否 ...

  3. java——字符串常量池、字符串函数以及static关键字的使用、数组的一些操作函数、math函数

    字符串常量池: 字符串比较函数:  字符串常用方法:  字符串截取函数: 字符串截取函数:  static关键字使用: 要调用类中的static类型的变量的时候,可以用"类名.变量名&quo ...

  4. Class常量池、运行时常量池、字符串常量池的一些思考

    Class常量池.运行时常量池.字符串常量池 class常量池 java代码经过编译之后都成了xxx.class文件,这是java引以为傲的可移植性的基石.class文件中,在CAFEBABE.主次版 ...

  5. Java String 常量池理解

    String:字符串常量池 作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以下三个问题,去理解字符串常量池: 字 ...

  6. String类、常量池、字符串比较

    String类.常量池.字符串比较 一:String类           1.String类又称作不可变字符序列           2.String位于java.lang包中,Java程序默认导入 ...

  7. 常量池之字符串常量池String.intern()

    运行时常量池是方法区(PermGen)的一部分. 需要提前了解: 1. JVM内存模型. 2. JAVA对象在JVM中内存分配 常量池的好处 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现 ...

  8. JVM 常量池、运行时常量池、字符串常量池

    常量池: 即class文件常量池,是class文件的一部分,用于保存编译时确定的数据. 保存的内容如下图: D:\java\test\out\production\test>javap -ver ...

  9. 彻底搞清楚class常量池、运行时常量池、字符串常量池

    彻底搞清楚class常量池.运行时常量池.字符串常量池 常量池-静态常量池 也叫 class文件常量池,主要存放编译期生成的各种字面量(Literal)和符号引用(Symbolic Reference ...

随机推荐

  1. python3练习100题——002

    因为特殊原因,昨天没有做题.今天继续- 原题链接:http://www.runoob.com/python/python-exercise-example2.html 题目: 企业发放的奖金根据利润提 ...

  2. 一个C语言程序是由( )组成?

    A) 一个主程序和若干子程序组成 B)一个或多个函数组成 C) 若干过程组成 D) 若干子程序组成 正确答案 B 解析 [解析] 一个C源程序是由一个main函数和若干个其他函数组成的.函数是C程序的 ...

  3. MySQL和MariaDB安全初始化

    通过yum安装mysql(5.x)后往往需要进行一些安全类的初始化设置: 安装完数据库后执行mysql_secure_installation命令,会出现安全相关的交互界面. 按提示操作.

  4. CSS操作

    CSS 与 JavaScript 是两个有着明确分工的领域,前者负责页面的视觉效果,后者负责与用户的行为互动.但是,它们毕竟同属网页开发的前端,因此不可避免有着交叉和互相配合. 1. 使用JavaSc ...

  5. Linux systemctl系统工具常用总结(详)

    systemctl是一个系统自带的服务管理工具,可以管理系统的服务的,启动.停止.重启.自启.监视.也可以对脚本程序后台运行管理. 文章以nginx.service举例 基础命令: systemctl ...

  6. opencv —— morphologyEx 开运算、闭运算、形态学梯度、顶帽、黑帽

    开运算:先腐蚀后膨胀. 能够排除小亮点. 闭运算:先膨胀后腐蚀. 能够排除小黑点. 形态学梯度:膨胀图 — 腐蚀图. 对二值图像进行这一操作,可将图块的边缘突出出来,故可用来保留物体边缘轮廓. 顶帽: ...

  7. Selenium实战(一)——浏览器实例

    一.Chrome浏览器 首先,在所有的打开浏览器操作之前,要配置好python环境和selenium,安装好如下图所示:然后可以选择一款适合自己的编辑器,这里用的是pycharm(第一次写博客贴的动图 ...

  8. [Python]PyCharm在创建py文件时自动添加头部注释

    在Pycharm主界面找到 File ----->> Setting ----->> Editor ----->> File and Code Templates ...

  9. 转: Laravel的数据库迁移 介绍的比较清晰

    原文: https://blog.sbot.io/articles/12/Laravel-数据库迁移(Database-Migrations)操作实例 很多人可能在学习Laravel框架的时候,对La ...

  10. VMware桥接模式下虚拟机ping主机不通

    现象: VMware设置为桥接模式,虚拟机ping主机不通,主机ping虚拟机通. 解决: 尝试以下几种方法 关闭主机(专用网络.来宾或公用网络)和虚拟机的防火墙. 更改桥接的物理网卡,确保是主机正在 ...