【问题标题】:String's Maximum length in Java - calling length() methodJava中字符串的最大长度-调用length()方法
【发布时间】:2010-10-23 09:38:52
【问题描述】:

Java 中,String 对象的最大大小是多少,参考 length() 方法调用?

我知道length()String 的大小返回为char []

【问题讨论】:

  • 虽然 String 的长度理论上是 Integer.MAX_VALUE,但源中字符串文字的长度似乎仅限于 UTF-8 数据的 65535 bytes

标签: java string


【解决方案1】:

考虑到String 类的length 方法返回int,该方法将返回的最大长度为Integer.MAX_VALUE,即2^31 - 1(或大约20 亿)。

在数组的长度和索引方面,(如char[],这可能是Strings内部数据表示的实现方式),The Java Language Specification, Java SE 7 EditionChapter 10: Arrays表示如下:

数组中包含的变量 没有名字;相反,他们是 由数组访问表达式引用 使用非负整数索引 价值观。这些变量称为 数组的组件。如果一个数组 有n 组件,我们说n 是 数组的长度;的组成部分 使用整数引用数组 从0n - 1 的索引,包括在内。

此外,索引必须按int 值,如Section 10.4 中所述:

数组必须由int 值索引;

因此,限制似乎确实是2^31 - 1,因为这是非负int 值的最大值。

但是,可能会有其他限制,例如数组的最大可分配大小。

【讨论】:

  • Integer.MAX_VALUE 实际上是 2^31-1。 :)
  • 很好的回答人!我看了一下String.java源码,没错,'count'是int变量,它返回char数组的长度,char数组存储在'value'变量上(如char[]),意思是字符串大小可能在 2GB 左右。当然,分配这样的内存大小可能会受到限制。谢谢!
  • 我刚刚尝试在一个长于 65546 的 hello world java 程序中定义一个字符串文字。javac 给出了一个关于该文字太长的错误:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
  • @dlamblin:这听起来像是javacString literals 的限制(不是String 对象),因为我找不到任何关于大小限制的参考String Java 语言规范和 JVM 规范中的文字。我尝试制作大于 100,000 个字符的 String 文字,Eclipse 编译器在编译它时没有问题。 (并且运行程序能够显示文字的 String.length 大于 100,000。)
  • @Premraj 那是三年前的事了,所以我不得不考虑一下。 ;) 我的意思是;要构建最大大小的字符串,您需要大量内存,可能比您拥有的更多。每个字符需要两个字节 ~ 4GB,但你需要从 StringBuilder 或 char[] 构建它,这意味着你首先需要每个字符另外两个字节来创建它,即另一个 ~ 4 GB(至少暂时)
【解决方案2】:

@987654321@@987654322@ 表示String 对象由两个字节 的长度信息和modified UTF-8 中的每个字符表示细绳。由此得出结论,当与DataInputDataOutput 一起使用时,String 的长度受到字符串的修改后的 UTF-8 表示的字节数的限制。

另外,Java虚拟机规范中的The specification of CONSTANT_Utf8_info定义结构如下。

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

你可以发现'length'的大小是两个字节

某个方法(例如String.length())的返回类型为int并不总是意味着其允许的最大值为Integer.MAX_VALUE。相反,在大多数情况下,选择int 只是出于性能原因。 Java 语言规范说,大小小于int 的整数在计算前会转换为int(如果我没记错的话),这是在没有特殊原因时选择int 的原因之一。

编译时的最大长度最多为 65536。再次注意,长度是 modified UTF-8 表示的字节数,而不是 String 对象中的字符数。

String 对象在运行时可能有更多的字符。但是,如果您想将String 对象与DataInputDataOutput 接口一起使用,最好避免使用太长的String 对象。我在实现 DataInput.readUTF()DataOutput.writeUTF(String) 的 Objective-C 等效项时发现了这个限制。

【讨论】:

  • 这应该是默认答案。
【解决方案3】:

由于数组必须使用整数进行索引,因此数组的最大长度为 Integer.MAX_INT(231-1 或 2 147 483 647)。当然,这是假设您有足够的内存来保存该大小的数组。

【讨论】:

    【解决方案4】:

    我有一台 2010 年的 iMac,内存为 8GB,运行 Eclipse Neon.2 Release (4.6.2) 和 Java 1.8.0_25。使用 VM 参数 -Xmx6g,我运行了以下代码:

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < Integer.MAX_VALUE; i++) {
        try {
            sb.append('a');
        } catch (Throwable e) {
            System.out.println(i);
            break;
        }
    }
    System.out.println(sb.toString().length());
    

    打印出来:

    Requested array size exceeds VM limit
    1207959550
    

    因此,最大数组大小似乎约为 1,207,959,549。然后我意识到我们实际上并不关心 Java 是否内存不足:我们只是在寻找最大数组大小(这似乎是在某处定义的常量)。所以:

    for (int i = 0; i < 1_000; i++) {
        try {
            char[] array = new char[Integer.MAX_VALUE - i];
            Arrays.fill(array, 'a');
            String string = new String(array);
            System.out.println(string.length());
        } catch (Throwable e) {
            System.out.println(e.getMessage());
            System.out.println("Last: " + (Integer.MAX_VALUE - i));
            System.out.println("Last: " + i);
        }
    }
    

    哪些打印:

    Requested array size exceeds VM limit
    Last: 2147483647
    Last: 0
    Requested array size exceeds VM limit
    Last: 2147483646
    Last: 1
    Java heap space
    Last: 2147483645
    Last: 2
    

    所以,最大值似乎是 Integer.MAX_VALUE - 2,或 (2^31) - 3

    附:我不知道为什么我的StringBuilder 达到了1207959550 而我的char[] 达到了(2^31)-3。似乎AbstractStringBuilder 将其内部char[] 的大小翻了一番以使其增长,因此这可能会导致问题。

    【讨论】:

    • 一个非常实用的问题处理方法
    【解决方案5】:

    显然它绑定到一个 int,即 0x7FFFFFFF (2147483647)。

    【讨论】:

      【解决方案6】:

      String类的length()方法的返回类型为int

      公共整数长度()

      参考http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length()

      所以int的最大值是2147483647

      String 内部被认为是 char 数组,所以索引是在最大范围内完成的。 这意味着我们无法索引第 2147483648 个成员。所以 java 中 String 的最大长度是 2147483647。

      原始数据类型int在java中是4字节(32位)。由于1位(MSB)用作符号位,范围限制在-2^31到2^31-1(-2147483648 到 2147483647)。 我们不能使用负值进行索引。所以显然我们可以使用的范围是从 0 到 2147483647。

      【讨论】:

        【解决方案7】:

        正如Takahiko Kawasaki's answer 中提到的,java 以modified UTF-8 的形式表示Unicode 字符串,而在JVM-Spec CONSTANT_UTF8_info Structure 中,为长度分配了2 个字节(而不是String 的字符数)。
        为了扩展答案,ASM jvm bytecode 库的 putUTF8 method 包含以下内容:

        public ByteVector putUTF8(final String stringValue) {
            int charLength = stringValue.length();
            if (charLength > 65535) {   
           // If no. of characters> 65535, than however UTF-8 encoded length, wont fit in 2 bytes.
              throw new IllegalArgumentException("UTF8 string too large");
            }
            for (int i = 0; i < charLength; ++i) {
              char charValue = stringValue.charAt(i);
              if (charValue >= '\u0001' && charValue <= '\u007F') {
                // Unicode code-point encoding in utf-8 fits in 1 byte.
                currentData[currentLength++] = (byte) charValue;
              } else {
                // doesnt fit in 1 byte.
                length = currentLength;
                return encodeUtf8(stringValue, i, 65535);
              }
            }
            ...
        }
        

        但是当码点映射>1byte时,它调用encodeUTF8方法:

        final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength /*= 65535 */) {
            int charLength = stringValue.length();
            int byteLength = offset;
            for (int i = offset; i < charLength; ++i) {
              char charValue = stringValue.charAt(i);
              if (charValue >= 0x0001 && charValue <= 0x007F) {
                byteLength++;
              } else if (charValue <= 0x07FF) {
                byteLength += 2;
              } else {
                byteLength += 3;
              }
            }
           ...
        }
        

        从这个意义上说,最大字符串长度为 65535 字节,即 utf-8 编码长度。而不是 char 计数
        您可以从上面的 utf8 结构链接中找到 JVM 修改后的 Unicode 代码点范围。

        【讨论】:

          猜你喜欢
          • 2016-11-23
          • 1970-01-01
          • 2012-07-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-26
          相关资源
          最近更新 更多