String究竟能存储多少字符?
能存储多少字符,通过以下步骤来看
- 首先String的length方法返回是int。所以理论上长度一定不会超过int的最大值。
- 编译器对字符串字面量长度的限制源自Java编译器(如
javac
)在处理常量池时的实现。编译器源码如下,限制了字符串长度大于等于65535就会编译不通过:// src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java
public class Pool {
// ... /**
* Add a new Utf8 string to the constant pool, checking for duplicates
* and sharing the entry if one already exists.
*/
public int putUtf8(String x) {
Assert.checkNonNull(x);
byte[] bytes;
try {
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);
dataoutputstream.writeUTF(x);
dataoutputstream.close();
bytes = bytearrayoutputstream.toByteArray();
} catch (IOException e) {
throw new AssertionError(e);
}
if (bytes.length > 65535)
throw new UTFDataFormatException("encoded string too long: " + bytes.length + " bytes");
return put(new Pool.Utf8Entry(bytes));
} // ...
}
Java中的字符常量都是使用UTF 8编码的,UTF 8编码使用1~4个字节来表示具体的Unicode字符。所以有的字符占用一个字节,而平时所用的大部分中文都需要3个字节来存储。
//65534个字母,编译通过
String s1 = "dd..d";
//21845个中文”自“,编译通过
String s2 = "自自...自";
//一个英文字母d加上21845个中文”自“,编译失败
String s3 = "d自自...自";
对于s1,一个字母d的UTF8编码占用一个字节,65534个字母占用65534个字节,长度是65534,长度和存储都没超过限制,所以可以编译通过。
对于s2,一个中文占用3个字节,21845个正好占用65535个字节,而且字符串长度是21845,长度和存储也都没超过限制,所以可以编译通过。
对于s3,一个英文字母d加上21845个中文”自“占用65536个字节,超过了存储最大限制,编译失败。
当然,这个限制是特定于编译器的实现,而不是Java语言本身的限制。
- JVM规范对常量池有所限制。
量池中的每一种数据项都有自己的类型。Java中的UTF-8编码的Unicode字符串在常量池中以CONSTANTUtf8
类型表示。CONSTANTUtf8
的数据结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
重点关注长度为 length 的那个bytes数组,这个数组就是真正存储常量数据的地方,而 length 就是数组可以存储的最大字节数,而不是字符数。length 的类型是u2,u2是无符号的16位整数,因此理论上允许的的最大长度是2^16-1=65535
。所以上面byte数组的最大长度可以是65535。
当然,考虑到UTF-8是一种变长编码,一个字符可能需要1到4个字节来表示(取决于字符的具体值)。因此,如果你的字符串包含大量使用多个字节编码的字符,那么它能包含的实际字符数将会少于65535。
- 运行时限制
String 运行时的限制主要体现在 String 的构造函数上。下面是 String 的一个构造函数:
public String(char value[], int offset, int count) {
...
}
上面的count值就是字符串的最大长度。在Java中,int的最大长度是2^31-1。所以在运行时,String 的最大长度是2^31-1。
但是这个也是理论上的长度,实际的长度还要看JVM的内存。来看下,最大的字符串会占用多大的内存。
(2^31-1)*16/8/1024/1024/1024 = 2GB
所以在最坏的情况下,一个最大的字符串要占用4GB的内存。如果JVM不能分配这么多内存的话,会直接报错的。
总结
因此,主要的还是看编译器对常量池的限制,使得byte数组的最大长度不能超过65535;以及JVM的内存限制
补充:JDK9以后对String的存储进行了优化。底层不再使用char数组存储字符串,而是使用byte数组。对于LATIN1字符的字符串可以节省一倍的内存空间。详情请看 Java9 - string字符串的变化
关于作者
来自一线程序员Seven的探索与实践,持续学习迭代中~
本文已收录于我的个人博客:https://www.seven97.top
公众号:seven97,欢迎关注~
String究竟能存储多少字符?的更多相关文章
- Java中String对象的存储位置(学习笔记)
首先,String是final修饰的.immutable对象,它以一个个字符的方式存储在字符数组中.其次,String类型创建对象有两种方式:①通过字面量赋值:会先去常量池中查找是否存在相同的字符串, ...
- MySQL 存储表情字符
摘要 在 MySQL 中直接存储表情的时候,会出现无法插入数据的错误. 这是由于一般情况下,MySQL 的字符集是 utf8,而对于 emoji 表情的 mysql 的 utf8 字符集是不支持,需要 ...
- mysql 无法存储表情字符 java.sql.SQLException: Incorrect string value: '\xF0\x9F\x90\xBE",...' for column 'XXXX' at row 1
1.变更字段类型 ALTER TABLE api_log MODIFY COLUMN remark longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_uni ...
- java中String常量的存储原理
相关题目(运行结果在代码注释后面) 1. package StringTest; public class test1 { public static void main(String[] args) ...
- 为什么 char 数组比 String 更适合存储密码?
推荐阅读:5 个刁钻的 String 面试题! 另一个基于 String 的棘手 Java 问题,相信我只有很少的 Java 程序员可以正确回答这个问题. 这是一个真正艰难的核心 Java 面试问题, ...
- String与基本类型,字符数组,字节数组的转换
String与基本数据类型 * 基本数据 --->字符串(String) * 1.基本数据类型值 +"" --->最简单 * 2.使用包装类中的toString(参数类 ...
- 为什么 char 数组比 Java 中的 String 更适合存储密码?
另一个基于 String 的棘手 Java 问题,相信我只有很少的 Java 程序员可以正确回答这个问题.这是一个真正艰难的核心Java面试问题,并且需要对 String 的扎实知识才能回答这个问题. ...
- [LeetCode] First Unique Character in a String 字符串第一个不同字符
Given a string, find the first non-repeating character in it and return it's index. If it doesn't ex ...
- [CareerCup] 1.1 Unique Characters of a String 字符串中不同的字符
1.1 Implement an algorithm to determine if a string has all unique characters. What if you cannot us ...
- XML中文本节点存储任意字符的方法
XML xml是一种可扩展标签语言, 为众多浏览器支持解析, ajax更是利用xml来完成服务器和客户端之前的通信. xml基本元素为 <label>xxx</label>, ...
随机推荐
- Linux内核中的static-key机制
# Linux内核中的static-key机制 背景 在移植某个TP时,发现频繁操作屏幕会导致i2c总线死掉.在跟踪代码的时候,我发现了这个static-key. 因此,学习一下这块的知识. refe ...
- shell 根据 指定列 进行 去除 重复行
根据指定列进行去除重复行 这里的重复是指如果两行的某一列数据相同,则认为是重复数据. 例如:第1行与第2行数据,其中的第2列(以- 作为分隔符)明显是重复的. 100069 - ARM Compile ...
- 背包DP——完全背包
完全背包模型与 0-1 背包类似,与 0-1 背包的区别仅在于一个物品可以选取无限次,而非仅能选取一次. 而状态转移方程于01背包区别在于可以直接从[i][j-w[i]]转移 理由是当我们这样转移时, ...
- 【论文阅读】Causal Imitative Model for Autonomous Driving
Sensor/组织: EPFL Sharif University of Technology Status: Finished Summary: 看看框架图就行.高效缓解因果混淆问题,将因果作为学习 ...
- Python 引用不确定的函数
在Python中,引用不确定的函数通常意味着我们可能在运行时才知道要调用哪个函数,或者我们可能想根据某些条件动态地选择不同的函数来执行.这种灵活性在处理多种不同逻辑或根据不同输入参数执行不同操作的场景 ...
- 【ClickHouse】7:clickhouse多实例安装
背景介绍: 有三台CentOS7服务器安装了ClickHouse HostName IP 安装程序 实例1端口 实例2端口 centf8118.sharding1.db 192.168.81.18 c ...
- 使用docker搭建ELK分式日志同步方案
ELK作为业界最常用日志同步方案,我们今天尝试一下使用docker快速搭建一套ELK方案.ELK使用国内加速源拉取的镜像比较旧,有条件的朋友可以拉取官网的源.elasticsearch作为日志储存库( ...
- 树莓派4B-GPIO控制舵机转动
树莓派4B-GPIO控制舵机转动 硬件需求: 树莓派 舵机 杜邦线 舵机 什么是舵机? 舵机(servomotor)是一种简化版本的伺服电机,是位置伺服的驱动器,能够通过输入PWM信号控制旋转角度,具 ...
- vue项目的简单创建与插件下载
准备工作 安装node.js 安装node.js过程全部采用默认配置,一步一步next即可 检验node.js是否安装成功:在cmd命令行中输入node -v以及npm -v 通过cmd创建 安装vu ...
- 简单万能队列状态机——WTYKAMC@2023
WTYKAMC@2023框架 [简介] 这是一个基于队列的灵活状态机,可以满足队列元素先进先出,先进后出,后进后出,后进先出,可以清除队列中未执行完的状态,且有一个默认超时执行状态:通过超时时间可以改 ...