java基础---String长度限制透彻解析

2023-05-16

文章目录

  • 前言
  • 一、String源码分析
  • 二、编译期常量池限制
    • 什么是码点?
  • 三、运行时期限制
  • 总结:

前言

在我们工作和学习中基本离不开Sring的数据类型,虽然我们经常接触到它但是一般很少会有人关心String是否会像int,long一样有范围限制。如果有的话又会是多少呢?首先我们直接揭晓答案,String类型是有长度限制的并且它在变异环境和运行时环境限制是不同的。下面我们会详细展开分析。

一、String源码分析

首先我们进入到String源码中看看是否能找到一些有用的线索,是否有直接对长度的限制或定义。String类中有很多重载的构造函数,其中有几个是支持用户传入length来定义长度的。可以看到,这里面的参数length是使用int类型定义的,那么也就是说,String定义的时候,最大支持的长度就是int的最大范围值。那么,我们是不是就可以认为String能支持的最大长度就是,java.lang.Integer#MAX_VALUE的最大值是2^31 - 1这个值了呢?事情当然没有那么简单,这个值只是在运行期,我们构造String的时候可以支持的一个最大长度,而实际上,在编译期,定义字符串的时候也是有长度限制的。
在这里插入图片描述
下面我就事实说话,这个字符串是我随便输出到控制台长度为10万的一个字符串。此时此刻它远远没有达到2^31 - 1但是却编译报错提示我们常量字符串过长。这又是为什么呢?
在这里插入图片描述
我们都知道,如我们所定义的“0123456789…”俗称字面量,在编译之后会以常量的形式进入到Class常量池。而常量池又是有所限制的,以至于间接性的限制了编译时期String的长度。

二、编译期常量池限制

我们知道,javac是将Java文件编译成class文件的一个命令,那么在Class文件生成过程中,就需要遵守一定的格式。根据 《Java虚拟机规范》中第4.4章节常量池的定义,CONSTANT_String_info 用于表示 java.lang.String 类型的常量对象,格式如下:
在这里插入图片描述
地址:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.3

Stirng 长度之所以会受限制,是因JVM规范对常量池有所限制。常量池中的每一种数据项都有自己的类型。其中,string_index 项的值必须是对常量池的有效索引, 常量池在该索引处的项必须是 CONSTANT_Utf8_info 结构,表示一组 Unicode 码点序列,这组 Unicode 码点序列最终会被初始化为一个 String 对象。
CONSTANT_Utf8的数据结构如下:

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

什么是码点?

在这里插入图片描述
上图出自:https://www.cnblogs.com/benbenalin/p/6921553.html

继续回到CONSTANT_Utf8_info其中,length则指明了 bytes[]数组的长度,其类型为u2,通过翻阅《规范》,我们可以获悉。u2表示两个字节的无符号数,那么1个字节有8位,2个字节就有16位。16位无符号数可表示的最大值位2^16 - 1 = 65535。也就是说,Class文件中常量池的格式规定了,其字符串常量的长度不能超过65535。

//65535个字符,编译报错
String s = "111111111......";

//65534个字符,编译通过
String s1 = "11111111......";

下图字符串s中包含65535个1编译出错,当我删除掉一个1时编译通过。这也直接验证了String编译时期的长度限制为65534
在这里插入图片描述
其实,这个原因在javac的代码中是可以找到的,在Gen类中有如下代码:

private void checkStringConstant(DiagnosticPosition var1, Object var2) {

    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的时候,就会导致编译失败。有兴趣的可以自己下一份源码翻阅下。其实,关于这个值,在《Java虚拟机规范》也有过说明:

if the Java Virtual Machine code for a method is exactly 65535 bytes long and ends with an instruction that is 1 byte 
long, then that instruction cannot be protected by an exception handler. A compiler writer can work around this bug by 
limiting the maximum size of the generated Java Virtual Machine code for any method, instance initialization method, or 
static initializer (the size of any code array) to 65534 bytes

如果方法的Java虚拟机代码恰好是65535字节长,并且以一条1字节长的指令结束,那么该指令就不能被异常处理程序保护。编译器编者可以通过将为任何方
法、实例初始化方法或静态初始化器(任何代码数组的大小)生成的Java虚拟机代码的最大大小限制为65534字节来解决这个问题

三、运行时期限制

上面我们提到在编译时期定义String s = “xxx”;最大为65534,那运行时期如果继续给这个变量追加字符串进去是否会报错呢?答案是不会,这里我就不进行演示了。那么它的边界限定又会是多少呢,总不能是无限大吧。当然不可能它的最大值就是我们前文提到的那个Integer.MAX_VALUE ,这个值约等于4G,在运行期,如果String的长度超过这个范围,就可能会抛出异常。(在jdk 1.9之前)

(2^31-1)*2*16/8/1024/1024/1024 = 4GB

所以在最坏的情况下,一个最大的字符串要占用4GB的内存。如果你的虚拟机不能分配这么多内存的话,会直接报错的。JDK9以后对String的存储进行了优化。底层不再使用char数组存储字符串,而是使用byte数组。对于LATIN1字符的字符串可以节省一倍的内存空间。

具体可以通过下图了解:
在这里插入图片描述
地址:https://www.cnblogs.com/flydean/p/jdk9-string-compact.html

总结:

字符串有长度限制,在编译期,要求字符串常量池中的常量不能超过65535,并且在javac执行过程中控制了最大值为65534。在运行期,长度不能超过Int的范围,否则会抛异常。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java基础---String长度限制透彻解析 的相关文章

  • 与 Eclipse 中的 Java Content Assist 交互

    作为我的插件项目的一部分 我正在考虑与 Eclipse 在 Java 文件上显示的内容辅助列表进行交互 我正在尝试根据一些外部数据对列表进行重新排序 我看过一些有关创建新内容辅助的教程 但没有看到有关更改现有内容辅助的教程 这可能吗 如果是
  • eclipse行号状态行贡献项是如何实现的?

    我需要更新状态行编辑器特定的信息 我已经有了自己的实现 但我想看看 eclipse 贡献项是如何实现的 它显示状态行中的行号 列位置 谁能指点一下 哪里可以找到源代码 提前致谢 亚历克斯 G 我一直在研究它 它非常复杂 我不确定我是否了解完
  • Thymeleaf 3 Spring 5 映射加载字符串而不是 HTML

    我正在尝试将 Spring 5 和 Thymeleaf 3 一起配置 我正在 Eclipse 上工作 我使用 全新安装 构建并使用 springboot run 运行应用程序 我已经设置了一个控制器和几个模板 但 Thymeleaf 似乎找
  • 如何在 Java 中向时间戳添加/减去时区偏移量?

    我正在使用 JDK 8 并且玩过ZonedDateTime and Timestamp很多 但我仍然无法解决我面临的问题 假设我得到了格式化的Timestamp在格林威治标准时间 UTC 我的服务器位于某处 假设它设置为Asia Calcu
  • Android studio - 如何保存先前活动中选择的数据

    这是我的代码片段 这Textview充当按钮并具有Onclicklistner在他们 当cpu1000时Textview单击它会导致cpu g1000其代码如下所示的类 public class Game 1000 extends AppC
  • 提供节点名或服务名,或未知 Java

    最近我尝试运行我的 Java 项目 每当我运行它并将其打开到我得到的服务器地址时 Unable to determine host name java net UnknownHostException Caused by java net
  • 如何在 ant 中为 junit 测试设置 file.encoding?

    我还没有完全完成file encoding 和 ant https stackoverflow com questions 1339352 how do i set dfile encoding within ants build xml
  • 如何成功地用 XML 中的批处理替换文本

    我尝试使用批处理在 XML 页面中替换字符串 但无法成功完全替换它 我有这个批处理代码 echo off setlocal EnableDelayedExpansion set search logLevel 3 set replace l
  • 蓝牙发送和接收文本数据

    我是 Android 开发新手 我想制作一个使用蓝牙发送和接收文本的应用程序 我得到了有关发送文本的所有内容逻辑工作 但是当我尝试在手机中测试它时 我看不到界面 这是Main Activity Code import android sup
  • 如何在JPanel中设置背景图片

    你好 我使用 JPanel 作为我的框架的容器 然后我真的想在我的面板中使用背景图片 我真的需要帮助 这是我到目前为止的代码 这是更新 请检查这里是我的代码 import java awt import javax swing import
  • 使用 Elastic Beanstalk 进行 Logback

    我在使用 Elastic Beanstalk 记录应用程序日志时遇到问题 我正在 AWS Elastic Beanstalk 上的 Tomcat 8 5 with Corretto 11 running on 64bit Amazon Li
  • 在 Java 中获取并存储子进程的输出

    我正在做一些需要我开始子处理 命令提示符 并在其上执行一些命令的事情 我需要从子进程获取输出并将其存储在文件或字符串中 这是我到目前为止所做的 但它不起作用 public static void main String args try R
  • JDBC 时间戳和日期 GMT 问题

    我有一个 JDBC 日期列 如果我使用 getDate 则会得到 date 仅部分2009 年 10 月 2 日但如果我使用 getTimestamp 我会得到完整的 date 2009 年 10 月 2 日 13 56 78 890 这正
  • 不可变的最终变量应该始终是静态的吗? [复制]

    这个问题在这里已经有答案了 在java中 如果一个变量是不可变的并且是final的 那么它应该是一个静态类变量吗 我问这个问题是因为每次类的实例使用它时创建一个新对象似乎很浪费 因为无论如何它总是相同的 Example 每次调用方法时都会创
  • 为什么\0在java中不同系统中打印不同的输出

    下面的代码在不同的系统中打印不同的输出 String s hello vsrd replace 0 System out println s 当我在我的系统中尝试时 Linux Ubuntu Netbeans 7 1 它打印 When I
  • 手动设置Android Studio的JDK路径

    如何为 Android Studio 使用自定义 JDK 路径 我不想弄乱 PATH 因为我没有管理员权限 是否有某个配置设置文件允许我进行设置 如果您查看项目设置 您可以从那里访问 jdk 在标准 Windows 键盘映射上 您可以在项目
  • 子类构造函数(JAVA)中的重写函数[重复]

    这个问题在这里已经有答案了 为什么在派生类构造函数中调用超类构造函数时 id 0 当创建子对象时 什么时候在堆中为该对象分配内存 在基类构造函数运行之后还是之前 class Parent int id 10 Parent meth void
  • Log4j2 ThreadContext 映射不适用于parallelStream()

    我有以下示例代码 public class Test static System setProperty isThreadContextMapInheritable true private static final Logger LOGG
  • Java/Python 中的快速 IPC/Socket 通信

    我的应用程序中需要两个进程 Java 和 Python 进行通信 我注意到套接字通信占用了 93 的运行时间 为什么通讯这么慢 我应该寻找套接字通信的替代方案还是可以使其更快 更新 我发现了一个简单的修复方法 由于某些未知原因 缓冲输出流似
  • Java 11 - 将 Spring @PostConstruct 替换为 afterPropertiesSet 或使用 initMethod

    我正在使用 spring 应用程序 有时会使用 PostConstruct用于代码和测试中的设置 看来注释将被排除在外Java 11 https www baeldung com spring postconstruct predestro

随机推荐

  • 计算机系统引导失败怎么办,电脑开机出现引导失败怎么办 是什么原因造成的...

    1 针对引导顺序被屏蔽 xff1a 开机后按DEL键进入CMOS设置 xff0c 选择主页面的第二项 Advanced BIOS Features 高级BIOS功能设定 在 高级BIOS功能 设定中选择First Boot Device 第
  • vs 开发 win32 程序,调出控制台窗口,方便调试

    设置方法 项目 gt 属性 gt 生成事件 gt 后期生成事件 gt 命令行 中添加 editbin span class hljs constant SUBSYSTEM span class hljs symbol CONSOLE spa
  • linux自动登录帐号密码,设定Linux自动登陆

    设定Linux自动登陆 在实验场景中我们可能会经常重新启动Linux xff0c 然后反复输入账户密码登陆 为了在每次启动后快速进入系统减少在实验场景中不必要的工作 xff0c 我们可以设定Linux在启动后自动登陆到指定账户 实验中一般为
  • 理解boot.img与静态分析Android/linux内核

    一些尝试和理解 1 gt 提取boot img xff1a 其中 xff0c msm代表是高通的芯片 xff0c msm sdcc 1是外接的SD卡挂载的目录 by name指的是这个sd卡分区的名称 下面几行代表每个分区存储的东西 记得提
  • c#读取json某一节点数据_C#解析json数据,如何通过下标值读取?

    关于Newtonsoft读取json数据 xff0c 在网上看到的都是使用JsonTextReader xff0c 然后 xff0c 通过while循环读取出来 如以下代码 xff1a string json 61 64 34 39 CPU
  • 如何恢复计算机工具栏,电脑任务栏怎么还原,教您怎么还原电脑任务栏

    在我们日常使用电脑中 xff0c 总会遇到一些问题 xff0c 例如windows系统中任务栏有时出现在右边 有时在上面 xff0c 这是怎么回事呢 xff1f 本来不影响操作的 xff0c 但是如果有强迫症的用户 xff0c 就一定得将其
  • cin、scanf、gets、getchar 用法介绍

    scanf是格式化输入 xff0c printf是格式化输出 cin是输入流 xff0c cout是输出流 效率稍低 xff0c 但书写简便 cout之所以效率低 xff0c 是先把要输出的东西存入缓冲区 xff0c 再输出 xff0c 导
  • BDA驱动学习笔记(1):功能拓扑图

    功能拓扑图 Functional Topology xff1a BAD的目标是不管硬件或者接收信号如何变 xff0c 它的整体架构可以不做大调整 xff0c 为此BDA引入功能拓扑图的概念 xff0c 它把类似DirectShow Filt
  • nproc systemd on CentOS 7

    Increasing nproc for processes launched by systemd on CentOS 7 Ask Question I have successfully increased the nofile and
  • MariaDB中文乱码之解决思路

    首先出现乱码的原因就是编码不一致问题引起的 xff0c 那么就从以下2个方面入手 xff1a 1 应用层 xff1a 前提条件数据库服务端存储的中文数据是对的 xff0c 但是页面上显示乱码 xff0c 这里只需要检查你的项目的编码格式 x
  • android预置权限,安卓预置应用的特权适配

    首先要理解特权应用 位于系统分区的priv app目录下的应用就是特权应用 普通三方应用只应包含normal和dangerous 运行时 级别的权限 xff0c 特权应用可能会增加signature和privileged级别的权限 如果在a
  • react里执行shouldComponentUpdate时返回false的后果

    大家都知道生命周期shouldComponentUpdate返回false时 xff0c 不会进行后续的渲染 xff0c 那这个时候state是什么情况呢 我们看一下demo class Toggle extends React Compo
  • 同比和环比的计算

    与上年度数据对比称 34 同比 34 xff0c 与上月数据对比称 34 环比 34 相关公式如下 xff1a 1 同比增长率计算公式 当年值 上年值 上年值x100 61 增长率 2 逆运算 a 已知当年值 和同比增长率这两个参数 xff
  • mysql出现10061错误解决方法

    首先要关闭MYSQL服务 关闭你现在正在运行的mysql数据库 xff0c 用结束mysql进程或者直接关闭mysql服务器都可以 1 开始菜单 gt 运行 xff08 cmd xff09 gt 寻径到MySQL文件中的bin目录下 如 x
  • 超市/饭店等收据或者小票的生成代码

    package com chauvet utils import java awt Color import java awt Font import java awt FontMetrics import java awt Graphic
  • SpringMVC配置顺序的问题

    1 web xml xff1a web应用一经加载 xff0c 先来找他 1 xff09 xff1a 指明applicationContext的位置 2 xff09 xff1a 引入spring监听 xff0c ContextLoaderL
  • OpenSSL.Net使用随记(二)

    前面已经把使用OpenSSL Net环境准备好了 xff0c 现在来调用几个常用算法的实现 MD5 xff0c SHA1 在这只需要注意下OpenSSL Crypto MessageDiges后面签名算法会用到 1 class Progra
  • 搭建Git服务器

    第一步 xff0c 安装git yum y install git 第二步 xff0c 创建一个git用户 xff0c 用来运行git服务 xff1a adduser git 第三步 xff0c 创建证书登录 xff1a 收集所有需要登录的
  • 修改VNCSERVER 默认的分辨率的方法

    vi usr bin vncserver 1024 找到默认的1024 768修改为 1680 1050 reboot 重启 转载于 https www cnblogs com del88 p 5656356 html
  • java基础---String长度限制透彻解析

    文章目录 前言一 String源码分析二 编译期常量池限制什么是码点 xff1f 三 运行时期限制总结 xff1a 前言 在我们工作和学习中基本离不开Sring的数据类型 xff0c 虽然我们经常接触到它但是一般很少会有人关心String是