文章目录

  • 前言
  • 一、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的范围,否则会抛异常。

java基础---String长度限制透彻解析相关推荐

  1. java基础-String字符串字符长度校验

    java基础-String字符串字符长度校验 /*** 校验字符串是否在规定字符数内* @param str* @param maxLength* @return*/ public static bo ...

  2. 靠java_基础不牢靠,何以争朝夕?Java基础面试82道详细解析!(一)

    基础不牢靠,何以争朝夕?Java基础面试82道详细解析!(一) 发布时间:2020-03-31 12:08:31 来源:51CTO 阅读:229 作者:wx5d9ed7c8443c3 题目的基本顺序是 ...

  3. 基础不牢靠,何以争朝夕?Java基础面试82道详细解析(更新中)

    题目的基本顺序是: 基本语法 类相关的语法 内部类的语法 继承相关的语法 异常的语法 线程的语法 集合的语法 io 的语法 虚拟机方面的语法 因文章篇幅的问题,本文分(一)(二)两篇进行讲解,知识点很 ...

  4. java中string长度有限制吗,最大是多少?

    这个问题其实还是有必要去谈一谈的,在我们进行字符串赋值的时候一般不会注意到string的长度什么的,因为一般达不到,但是有个特殊的字符串比较长,那就是Base64转码: base64是进行图片传输的时 ...

  5. java基础----String、StringBuffer、StringBuilder

    1.String package com.henu;public class Demo05 {public static void main(String[] args) {/** 字符串是常量:它们 ...

  6. 【java进阶之路】(Java基础篇)[扩展]深入解析String.intern()及字符串常量池问题

    申明 : 此文仅仅作为个人学习使用 , 如果有人对于String.intern() 十分想要究其原理 , 请参考此文深入解析String#intern - 美团技术团队 8种基本类型的常量池都是系统协 ...

  7. Java基础教程(全代码解析)

    字面量: 整数字面量为整型(int) 小数字面量为双精度浮点型(double) 数据类型: byte short int long float double 接下来代码展示理解 public clas ...

  8. Java基础测试选择题带答案解析(一)

    1.[单选题] 对于代码: public void test(int[] arr) { int i, j, note; for (i = 1; i < arr.length; i++) { no ...

  9. Java基础——String类(一)

    一.String 类代表字符串 Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现. 字符串是常量:它们的值在创建之后不能更改.字符串缓冲区支持可变的字符串 ...

最新文章

  1. OpenCV-Python:K值聚类
  2. TP-link 设置MAC地址过滤
  3. 【回顾】紫丁香一队的故事
  4. 区块链BaaS云服务(21)腾讯CCGP“跨链服务”
  5. Redis中的发布与订阅的概念与以命令行的方式实现发布订阅举例
  6. 贾斯帕马斯基林的故事笔记
  7. vue2.0 非父子组件之间的单一事件通信
  8. java io图_JAVA IO流结构图
  9. 接口测试系列:工作中所用(十:配置文件的读写操作 configparser模块)
  10. Xcode - Plugins And Themes
  11. ILSVRC2012神经网络训练图像预处理
  12. python环境下skimage处理高通道tif图片(10通道)
  13. SQLite在指定列后面插入字段_如何用SQL语句添加和修改字段?
  14. 端午节了,了解粽子的起源
  15. 怎么确定K均值聚类中的K(基于matlab)
  16. 2012 5.4青年节--上海出差
  17. Wireshark抓取TCP三次握手包
  18. eclipse 显示 空格 .回车符号,去掉相应的符号
  19. Field myFeignClient in com.zkh.controller.FeignController required a bean of type 'com.zkh.feign.MyF
  20. python 中关键字 global 的用法

热门文章

  1. 普鲁斯特问卷的26个问题
  2. 哪款无线耳机音质好?音质不错的蓝牙耳机推荐
  3. yolo v5 损失函数分析
  4. 物联卡中心:快手上买物联卡是真的吗?小心陷入“骗局”!
  5. 统一javaweb项目和mysql数据库时间UTC时间方法及原理
  6. 安排,Elasticsearch Stack深入浅出视频教程
  7. vue项目全局引入jquery
  8. 汽车科目一学习考试系统
  9. 中拓互联解密:一个购物码,可以玩出什么花样?
  10. MYSQL 初始密码