写点什么

java String 长度有限制吗?

用户头像
ddww
关注
发布于: 2021 年 03 月 18 日
java String长度有限制吗?

引言

今天读了一篇关于 java 中 String 长度限制的文章。读完之后,感觉更懵。所以就想自己总结一下这个问题,本文以 jdk1.8 为例进行分析,加深理解。

String 长度有限制

我用标题回答这个问题。这个长度主要分为编译期限制和运行期限制。

编译期限制

JVM 在编译中有自己的规范,String 类型的字面量存储在 JVM 字符串常量池中。CONSTANT_String_info 用于表示 java.lang.String 类型的常量对象,格式如下:

CONSTANT_String_info{  u1 tag;  u2 string_index;}
复制代码
  • tag: 常量类型->CONSTANT_String(8 字节)

  • string_index:表示常量池的有效索引,其结构为 CONSUTANT_Utf8_info。表示一组 Unicode 码点序列,通过这组码点序列最终被初始化为一个 String 对象。

CONSUTANT_Utf8_info{  u1 tag;  u2 length;  u1 bytes[length];}
复制代码

这样就很好分析,String 在编译期的限制就是 length 的长度。u2 表示无符号位 2 个单字节的长度,一个字节占 8 位,则 u2(11111111 11111111)表示的范围为 0~2^16-1。那么其范围是[0~65535]。接下来我们进行测试,结论是否正确。

    public static void main(String[] args) {        String str="qqqqqq...";//长度为65535的字符串,这里简写        System.out.println(str.length());    }
复制代码

进行编译运行,结果却是:

java: 常量字符串过长
复制代码

发现编译过程中竟然报错了,我们继续往下探究。编译是由 javac 进行编译的,感兴趣的小伙伴可自行下载 javac 的源码包http://hg.openjdk.java.net/jdk8/jdk8/langtools/。其中有两段代码,这样写道

    private void checkStringConstant(DiagnosticPosition pos, Object constValue) {        if (nerrs != 0 || // only complain about a long string once            constValue == null ||            !(constValue instanceof String) ||            ((String)constValue).length() < Pool.MAX_STRING_LENGTH)            return;        log.error(pos, "limit.string");        nerrs++;    }
复制代码

Pool.MAX_STRING_LENGTH 的长度究竟是多少,继续往下看

public class Pool {  ...      public static final int MAX_STRING_LENGTH = 0xFFFF;    ...   }
复制代码

经过 Pool.MAX_STRING_LENGTH 为 0xFFFF 转化成 65535,因为要小于它,所以 length 的最大长度为 65534。进行测试

    public static void main(String[] args) {        String str="qqqqqq...";//长度为65534的字符串,这里简写        System.out.println(str.length());//编译通过,运行成功    }
复制代码

在开发过程中,有时确实需要复制一大段字符串进行测试。但是往往会编译失败,其原因就是我们使用的是默认的编译期 javac,如何解决呢?以 idea 举例说明。File->Settings,搜索 java Compiler

选择 Eclipse,点击 Apply。这样,我们就将编译器设置为 JDT,JDT 优化为了 StringBuilder 的 append 的方式。

运行时限制

运行时限制就相对简单一些了,查看 String 源码即可找出答案。

public final class String    implements java.io.Serializable, Comparable<String>, CharSequence {    ...        private final char value[];        public int length() {        return value.length;    }        ...    }
复制代码

String 的长度用 int 类型表示,int 占四个字节,就是 32 位,其长度为 2^31-1,约等于 4GB。

总结

  1. java 中的字符串常量,编译期是 javac 的话,其最大长度为 65534。换句话说,JVM 虚拟机中的字符串常量池,一个 String 对象最多存 65534 字符。

  2. java 运行期间,String 的最大长度为 4GB,这时 String 对象在堆中存放。

  3. Eclipse 有自己的 java 编译器,JDT 优化为了 StringBuilder 的 append。StringBuilder 在 toString 的过程中,相当于重新 new 了一个 String 对象,存放在堆中。

  4. 第四点借用下面的引用

Eclise 使用自己的编译器。主要原因是 JDT 核心具有渐进式编译的能力,这意味着它会逐步编译代码中的更改(这也是 Eclipse 不需要编译按钮的原因,因为它会在检测到更改时自动编译)。但 Oracle 的 JDK 不支持增量编译

参考


发布于: 2021 年 03 月 18 日阅读数: 24
用户头像

ddww

关注

还未添加个人签名 2018.07.21 加入

还未添加个人简介

评论 (1 条评论)

发布
用户头像
写的很棒,支持一下
2021 年 03 月 18 日 14:35
回复
没有更多了
java String长度有限制吗?