String 最多能存储多少个字符/String 字符串的最大长度/String 字符串有没有长度限制

本文主要是介绍String 最多能存储多少个字符/String 字符串的最大长度/String 字符串有没有长度限制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1.编译时字节限制
  • 2.运行时长度限制
  • 3.小结
  • 4.补充

基于 JDK8 进行分析

1.编译时字节限制

String s = "11111...1111"; // 其中有 10 万个字符 "1"

当我们使用如上形式定义一个字符串的时候,当我们执行 javac 编译时,是会抛出异常的,提示 java: constant string too long

javac 是用于将 Java 源文件编译成 class 字节码二进制文件,那么在 class 文件生成过程中,就需要遵守一定的规范。

根据《Java 虚拟机规范》中对常量池的定义,CONSTANT_String_info 用于表示 java.lang.String 类型的常量对象,格式如下:

 CONSTANT_String_info {u1 tag;u2 string_index;
}

其中,string_index 项的值必须是对常量池的有效索引,常量池在该索引处的项必须是 CONSTANT_Utf8_info 结构,表示一组 Unicode 码点序列,这组 Unicode 码点序列最终会被初始化为一个 String 对象。

CONSTANT_Utf8_info 结构用于表示字符串常量的值:

CONSTANT_Utf8_info {u1 tag;u2 length;u1 bytes[length];
}

其中,length 则指明了 bytes[] 数组的长度,其类型为 u2,即两个字节的无符号数,那么其可表示的最大值为 2 16 − 1 = 65535 2^{16} - 1 = 65535 2161=65535

也就是说,编译时生成的 class 文件中的字符串常量的字节数不能超过 65535。

但即使我们定义了一个由 65535 个 “1” 组成的字符串,还是会允许报错,报错原因还是 java: constant string too long

这个原因可以在 javactools.jar 包中找到,在 com.sun.tools.javac.jvm.Gen 类中有如下方法:

private void checkStringConstant(JCDiagnostic.DiagnosticPosition var1, Object var2) {// String.length() >= 65535 就抛出异常if (this.nerrs == 0 && var2 != null && var2 instanceof String && ((String)var2).length() >= 65535) {this.log.error(var1, "limit.string", new Object[0]);++this.nerrs;}
}

当参数类型为 String,并且长度大于等于 65535 的时候,就会导致编译失败。

为什么最大长度是 65534 而不是 65535 呢?这是 Java 虚拟机历史上的一个设计缺陷:如果 Java 虚拟机中的一个方法的 code 属性的长度刚好是 65535 个字节,并且以一个 1 个字节长度的指令结束,那么这条指令将不能被异常处理器所处理。不过编译器可以通过限制任何方法、实例初始化方法或类初始化方法的 code[] 数组最大长度为 65534,这样可以间接弥补这个 BUG。

所以,综合 CONSTANT_Utf8_info 中的 length 大小限制与 javac 检查机制,字符串常量的最大字节数为 65535,最大长度为 65534。

Java 中的字符常量都是使用 UTF8 编码的,UTF8 编码使用 1~4 个字节来表示具体的 Unicode 字符。所以有的字符占用一个字节,而我们平时所用的大部分中文都需要 3 个字节来存储。

// 65534 个字母,编译通过
String s1 = "dd..d";// 21845 个中文 “自”,编译通过
String s2 = "自自...自";// 一个英文字母 d 加上 21845 个中文 “自”,编译失败
String s3 = "d自自...自";
  • 对于 s1,一个字母 d 的 UTF8 编码占用 1 个字节,65534 字母占用 65534 个字节,长度是 65534,字节数与长度都没有超出限制,所以可以编译通过。
  • 对于 s2,一个中文占用 3 个字节,21845 个正好占用 65535 个字节,而且字符串长度是 21845,字节数与长度都没有超出限制,所以可以编译通过。
  • 对于 s3,一个英文字母 d 加上 21845 个中文“自”占用 65536 个字节,超过了最大字节数,编译失败。

2.运行时长度限制

public int length() {return value.length;
}

String 类提供了一个 length() 方法,返回值为有符号的 32 位的 int 类型,所以理论上 String 的最大长度为 2 31 − 1 2^{31} -1 2311,因此在最大长度情况下占用内存约 ( 2 31 − 1 ) ∗ 2 ∗ 16 / 8 / 1024 / 1024 / 1024 = 4 G B (2^{31}-1)*2*16/8/1024/1024/1024 = 4GB (2311)216/8/1024/1024/1024=4GB​。如果 JVM 不能分配这么多内存的话,会出现 OOM 内存不足错误。

// success
public class Main {public static void main(String[] args) throws IOException {String s = "";for (int i = 0; i < 100000; i++) {s += "1";}// 100000System.out.println(s.length());System.out.println(s);}
}

3.小结

String 在不同的时期,具有不同的长度限制。

  • 编译时限制:UTF8 编码的字符串常量的最大字节数为 65535,最大长度为 65534
  • 运行时限制:字符串的长度不能超过 2 31 − 1 2^{31}-1 2311,且占用的内存不能超过当前虚拟机还能够提供的最大值。

4.补充

JDK9 以后对 String 的存储进行了优化。底层不再使用 char 数组存储字符串,而是使用 byte 数组。对于 LATIN1 字符的字符串可以节省一倍的内存空间。

这篇关于String 最多能存储多少个字符/String 字符串的最大长度/String 字符串有没有长度限制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/945706

相关文章

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

一文详解如何在Python中从字符串中提取部分内容

《一文详解如何在Python中从字符串中提取部分内容》:本文主要介绍如何在Python中从字符串中提取部分内容的相关资料,包括使用正则表达式、Pyparsing库、AST(抽象语法树)、字符串操作... 目录前言解决方案方法一:使用正则表达式方法二:使用 Pyparsing方法三:使用 AST方法四:使用字

Java字符串处理全解析(String、StringBuilder与StringBuffer)

《Java字符串处理全解析(String、StringBuilder与StringBuffer)》:本文主要介绍Java字符串处理全解析(String、StringBuilder与StringBu... 目录Java字符串处理全解析:String、StringBuilder与StringBuffer一、St

MySQL更新某个字段拼接固定字符串的实现

《MySQL更新某个字段拼接固定字符串的实现》在MySQL中,我们经常需要对数据库中的某个字段进行更新操作,本文就来介绍一下MySQL更新某个字段拼接固定字符串的实现,感兴趣的可以了解一下... 目录1. 查看字段当前值2. 更新字段拼接固定字符串3. 验证更新结果mysql更新某个字段拼接固定字符串 -

Java String字符串的常用使用方法

《JavaString字符串的常用使用方法》String是JDK提供的一个类,是引用类型,并不是基本的数据类型,String用于字符串操作,在之前学习c语言的时候,对于一些字符串,会初始化字符数组表... 目录一、什么是String二、如何定义一个String1. 用双引号定义2. 通过构造函数定义三、St

golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法

《golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法》:本文主要介绍golang获取当前时间、时间戳和时间字符串及它们之间的相互转换,本文通过实例代码给大家介绍的非常详细,感兴趣... 目录1、获取当前时间2、获取当前时间戳3、获取当前时间的字符串格式4、它们之间的相互转化上篇文章给大家介

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义