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

  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. Android/SELinux 添加 AVC 权限

    Android/SELinux 添加 AVC 权限 背景 在Android应用层中编写c/c++应用时,发现接口调用出现问题,logcat才知道是因为:权限不够. type=1400 audit(0. ...

  2. Android 中的 perfboot工具

    背景 开机首先加载bootloader,由bootloader启动kernel,然后运行init程序,有init启动Zygote,Zygote进程启动SystemServ进程,在SystemServe ...

  3. B 站和小红书又又又崩了,罪魁祸首竟然又是他。。。

    大家好,我是凌晨. 今天上午10点左右,我打开B站发现无法刷新视频列表和评论区,收藏夹和弹幕也均不可用. 原以为是手机网络问题,换网络重启手机都还是不行,第一时间打开微博,果然,B站崩了的新闻荣登榜首 ...

  4. ABC195E

    其实我们发现很多博弈论的动态规划都是从后往前的,比如过河卒和本题. 这是因为从某种角度上来说这些动态规划有后效性而无前效性. 所以设计状态 \(dp_{i,j}\) 表示第 \(i\) 次操作 \(T ...

  5. Java智能之Spring AI:5分钟打造智能聊天模型的利器

    前言 尽管Python最近成为了编程语言的首选,但是Java在人工智能领域的地位同样不可撼动,得益于强大的Spring框架.随着人工智能技术的快速发展,我们正处于一个创新不断涌现的时代.从智能语音助手 ...

  6. 小程序-云数据库的add,get,remove,update

    云数据库的使用就是使用简单的原生封装wx.cloud.database().collection("list"),然后就是add,get,remove,update四个方法 初始化 ...

  7. AT_abc246_d 题解

    洛谷链接&Atcoder 链接 本篇题解为此题较简单做法及较少码量,并且码风优良,请放心阅读. 题目简述 给定整数 \(N\),请你找到最小的整数 \(X\),满足: \(X \ge N\). ...

  8. Docker 基于Dockerfile创建镜像实践

    需求描述 简单说,就是创建一个服务型的镜像,即运行基于该镜像创建的容器时,基于该容器自动开启一个服务.具体来说,是创建一个部署了nginx,uwsgi,python,django项目代码的镜像,运行基 ...

  9. 浅谈Git架构和如何避免代码覆盖的事故

    浅谈Git架构和如何避免代码覆盖的事故 Git 不同于 SVN 的地方在于, Git 是分布式的版本管理系统, 所有的客户端和服务器都保存了一份代码, 涉及到仓库仓之间的同步, 所以处理不当极易造成冲 ...

  10. 【Java】Input,Output,Stream I/O流 05 RandomAccessFile 随机访问文件类

    RandomAccessFile 随机访问文件类 直接继承java.lang.Object 实现DataInput & DataOutput 接口 即是输入流,也是输出流 public cla ...