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>, ...
随机推荐
- Qt 之 emit、signals、slot的使用
背景 ref : https://www.ibm.com/developerworks/cn/linux/guitoolkit/qt/signal-slot/index.html 信号和槽机制是 QT ...
- win11 vmware16 启动虚拟机引起蓝屏
前言 在win11 上安装 vmware16, 之后安装ubuntu16时,一打开ubuntu虚拟机就触发系统蓝屏. 正文 我改了两个地方: 控制面板->程序->启用或关闭Windows功 ...
- 微调 Florence-2 - 微软的尖端视觉语言模型
Florence-2 是微软于 2024 年 6 月发布的一个基础视觉语言模型.该模型极具吸引力,因为它尺寸很小 (0.2B 及 0.7B) 且在各种计算机视觉和视觉语言任务上表现出色. Floren ...
- Display、Visibility 和 Opacity 的区别
<style> .d1{ display: none; } .d2{ visibility: visible; } .d3{ opacity: 0; } </style> &l ...
- 引入样式在Element UI (Vue 2)和Element Plus (Vue 3)中的不同
引入样式 Element UI (Vue 2): import 'element-ui/lib/theme-chalk/index.css'; Element Plus (Vue 3): im ...
- [oeasy]python0137_相加运算_python之禅_import_this_显式转化
变量类型 相加运算 回忆上次内容 上次讲了是从键盘输入变量 input 函数 可以有提示字符串 需要有具体的变量接收输入的字符串 输入单个变量没有问题 但是输入两个变量之后 一相加就非常离谱 ...
- VSCode最强插件推荐(持续更新)
一.通用插件 Codelf 描述:变量命名神器 Bracket Pair Colorizer 描述:成对的彩色括号,让括号拥有独立的颜色,便于区分 Prettier - Code formatter ...
- C#封装HttpClient工具类库(.NET4.5以上)
1.Json字符串实体转换扩展方法,依赖Json.Net包 /// <summary> /// Json扩展方法 /// </summary> public static cl ...
- Goutte爬虫
安装 composer require fabpot/goutte:4.0
- jmeter forEach循环获取response参数值进行接口请求
jmeter forEach循环获取response参数值进行接口请求 注意: 一,ForEach控制器 输入变量前缀:输入正则表达式变量的引用名称即可 Start index for loop(ex ...