能存储多少字符,通过以下步骤来看

  1. 首先String的length方法返回是int。所以理论上长度一定不会超过int的最大值。
  2. 编译器对字符串字面量长度的限制源自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语言本身的限制。

  1. 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。

  1. 运行时限制

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究竟能存储多少字符?的更多相关文章

  1. Java中String对象的存储位置(学习笔记)

    首先,String是final修饰的.immutable对象,它以一个个字符的方式存储在字符数组中.其次,String类型创建对象有两种方式:①通过字面量赋值:会先去常量池中查找是否存在相同的字符串, ...

  2. MySQL 存储表情字符

    摘要 在 MySQL 中直接存储表情的时候,会出现无法插入数据的错误. 这是由于一般情况下,MySQL 的字符集是 utf8,而对于 emoji 表情的 mysql 的 utf8 字符集是不支持,需要 ...

  3. 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 ...

  4. java中String常量的存储原理

    相关题目(运行结果在代码注释后面) 1. package StringTest; public class test1 { public static void main(String[] args) ...

  5. 为什么 char 数组比 String 更适合存储密码?

    推荐阅读:5 个刁钻的 String 面试题! 另一个基于 String 的棘手 Java 问题,相信我只有很少的 Java 程序员可以正确回答这个问题. 这是一个真正艰难的核心 Java 面试问题, ...

  6. String与基本类型,字符数组,字节数组的转换

    String与基本数据类型 * 基本数据 --->字符串(String) * 1.基本数据类型值 +"" --->最简单 * 2.使用包装类中的toString(参数类 ...

  7. 为什么 char 数组比 Java 中的 String 更适合存储密码?

    另一个基于 String 的棘手 Java 问题,相信我只有很少的 Java 程序员可以正确回答这个问题.这是一个真正艰难的核心Java面试问题,并且需要对 String 的扎实知识才能回答这个问题. ...

  8. [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 ...

  9. [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 ...

  10. XML中文本节点存储任意字符的方法

    XML xml是一种可扩展标签语言, 为众多浏览器支持解析, ajax更是利用xml来完成服务器和客户端之前的通信. xml基本元素为 <label>xxx</label>, ...

随机推荐

  1. python重拾第五天-常用模块学习

    本节大纲: 模块介绍 time &datetime模块 random os sys shutil json & picle shelve xml处理 yaml处理 configpars ...

  2. Linux驱动中的异步函数(aio_read和aio_write)

    Linux驱动中的异步函数(aio_read和aio_write) 我们可以在signal_handler使用了read和write函数处理设备文件的读写操作.然而这两个函数可以分别用aio_read ...

  3. welcome to chifan-duck's blog

    博主简介 截至至 2024 博主事一名初二学生. 为什么开博客园 因为博主是一名 Oier. 博客内容 OI 知识(科技)的普及 & 题解 为什么叫 chifan-duck ? 原本博主再各大 ...

  4. 在linux系统中,对标准输出(stdout,文件描述符为 1)和标准错误(stderr,文件描述符为 2)重定向到文件

    请参考:2>/dev/null和>/dev/null 2>&1和2>&1>/dev/null的区别 下面的是本人浅尝辄止了,并非全貌,还是上面的文章说的比 ...

  5. nodejs-mime类型

    mime是一个互联网标准,通过设定它就可以设定文件在浏览器的打开方式. mime使用方法: 使用mime模块查询文件的MIME类型: mime.getType('/path/to/file.txt') ...

  6. 使用了条件三元运算符来判断 this.temp.id 是否存在且 mt_qty 是否已被赋值

    mt_qty: (this.temp.id && this.temp.mt_qty) ? this.temp.mt_qty : event.wo_wip,在这个修正后的代码中,使用了条 ...

  7. 数据分析应该掌握的知识及SQL技能

    一.概念及常识 1.数据分析必备的统计学知识 描述统计学 1.平均值.中位数.众数 2.方差.标准差 3.统计分布:正态分布.指数分布.二项分布.卡方分布 推论统计学 1.假设检验 2.置信区间 3. ...

  8. C#全局键盘监听(Hook)的使用

    一.为什么需要全局键盘监听? 在某些情况下应用程序需要实现快捷键执行特定功能,例如大家熟知的QQ截图功能Ctrl+Alt+A快捷键,只要QQ程序在运行(无论是拥有焦点还是处于后台运行状态),都可以按下 ...

  9. 在Eclipse中使用Project Explorer视图与Package Explorer视图

    1.在项目文件比较多的情况下,为了方便查看整体和及时定位到项目文件,通常会同时使用Project Explorer视图与Package Explorer视图. 2.打开Project Explorer ...

  10. Python 按比例获取样本数据或执行任务

    按比例获取样本数据或执行任务 By:授客 QQ:1033553122 开发环境 win 10 python 3.6.5 需求 已知每种分类的样本占比数,及样本总数,需要按比例获取这些分类的样本.比如, ...