Javaでの文字列の最大長-length()メソッドの呼び出し


150

ではJavaの最大サイズ何Stringを参照して、オブジェクトが持つlength()メソッドの呼び出し?

length()aのサイズをStringとして返すことは知っていchar []ます。


5
aの長さStringは理論的Integer.MAX_VALUEにはですが、ソース内の文字列リテラルの長さは、UTF-8データの65535バイトのみに制限されているようです。
200_success

回答:


169

考慮Stringクラスのlengthメソッドの戻りはint、メソッドによって返される最大長は次のようになりInteger.MAX_VALUEである、2^31 - 1(又は約20億)。

長さと配列のインデックス作成の観点から、(例えば、char[]おそらく、内部データ表現をするために実装される方法である、StringS)、第10章:アレイJava言語仕様のJava SE 7 Editionは、次のように述べています。

配列に含まれる変数には名前がありません。代わりに、非負の整数インデックス値を使用する配列アクセス式によって参照されます。これらの変数は、配列のコンポーネントと呼ばれ ます。配列にnコンポーネントがある場合は、配列n長さです。配列のコンポーネントは、から0までの整数インデックスを使用して参照されn - 1ます。

さらに、10.4項intで説明したように、インデックスは値である必要があります。

配列にはint値でインデックスを付ける必要があります。

したがって、それ2^31 - 1は非負のint値の最大値であるため、制限は確かにであるように見えます。

ただし、おそらく配列に割り当て可能な最大サイズなど、他の制限もあるでしょう。


26
Integer.MAX_VALUEは実際には2 ^ 31-1です。:)
マイケルマイヤーズ

1
素晴らしい答えの男!String.javaソースコードを調べたところ、そうです、 'count'はchar配列の長さを返すint変数であり、char配列は 'value'変数に格納されています(char []として)文字列のサイズは約2GBになる可能性があります。もちろん、そのようなメモリサイズを割り当てるには制限があるかもしれません。ありがとう!
太一、

5
私はちょうど65546.よりも長かったハローワールドJavaプログラム内の文字列リテラルを定義しようとしたjavacが長すぎるというリテラルであることについてエラーを与える:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
dlamblin

2
@dlamblin:の制限のような音つまりjavacためString リテラル(不Stringiはサイズ制限への参照を見つけることができないなどのオブジェクト)、StringJava言語仕様とJVM仕様でリテラル。String100,000文字を超えるリテラルを作ってみましたが、Eclipseコンパイラーではコンパイルに問題がありませんでした。(そして、プログラムを実行すると、リテラルがString.length100,000より大きいことが示されました。)
coobird

3
@Premrajそれは3年前だったので、私はそれについて考えなければなりませんでした。;)私が言ったことは、最大サイズの文字列を作成するには、おそらく多くのメモリが必要です。文字あたり2バイト〜4GBが必要ですが、これをStringBuilderまたはchar []から構築する必要があります。つまり、最初にそれを作成するには、文字あたりさらに2バイトが必要です。つまり、別の〜4 GB(少なくとも一時的に)
ピーターローリー

25

java.io.DataInput.readUTF()またjava.io.DataOutput.writeUTF(String)Stringオブジェクトは2バイトの長さ情報と、文字列内のすべての文字の変更されたUTF-8表現で表されると言います。これにより、DataInputおよびで使用した場合、文字列の長さは文字列の変更されたUTF-8表現のバイト数によって制限されますDataOutput

また、仕様CONSTANT_Utf8_info次のようにJava仮想マシンの仕様に見られる構造を定義します。

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

「長さ」のサイズが2バイトであることがわかります

特定のメソッド(たとえばString.length())の戻り値の型がint常に許容最大値であるとは限りませんInteger.MAX_VALUE。代わりに、ほとんどの場合、intパフォーマンス上の理由で選択されます。Java言語仕様では、サイズがそれよりも小さい整数は計算前にint変換されると記述されておりint(私のメモリが正しく機能している場合)、int特別な理由がない場合に選択する理由の1つです。

コンパイル時の最大長は最大65536です。長さは、オブジェクト内の文字数ではなく、変更されたUTF-8表現のバイト数であることに注意してくださいString

Stringオブジェクトは、実行時により多くの文字を持つことができる場合があります。ただし、Stringオブジェクトをインターフェースで使用する場合はDataInputDataOutput長すぎるオブジェクトを使用しないことをお勧めしStringます。私はのObjective-Cの等価物を実現するとき、この制限を発見DataInput.readUTF()し、DataOutput.writeUTF(String)


1
これがデフォルトの答えです。
Nick、

20

配列には整数でインデックスを付ける必要があるため、配列の最大長はInteger.MAX_INT(2 31 -1、または2 147 483 647)です。もちろん、そのサイズの配列を保持するのに十分なメモリがあることを前提としています。


9

8GBのRAMを搭載した2010 iMacを使用しており、Java 1.8.0_25を搭載したEclipse Neon.2リリース(4.6.2)を実行しています。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のようです

PS私はなぜ(2 ^ 31)-3で最大StringBuilder1207959550なり、char[]最大になっているのかわかりません。それはそれを成長させるためAbstractStringBuilderにその内部のサイズを2倍char[]にするようです、それでおそらく問題を引き起こします。


1
質問の非常に実用的な扱い
パブロマイストレンコ


4

Stringクラスのlength()メソッドの戻り値の型はintです。

public int length()

http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length()を参照してください

したがって、intの最大値は2147483647です。

文字列は内部的にchar配列と見なされるため、インデックス付けは最大範囲内で行われます。これは、2147483648番目のメンバーにインデックスを付けることができないことを意味します。JavaのStringの最大長は2147483647です。

プリミティブデータ型intは、javaでは4バイト(32ビット)です。1ビット(MSB)が符号ビットとして使用されるため、範囲は-2 ^ 31〜2 ^ 31-1(-2147483648〜2147483647)内に制限されます。インデックスに負の値を使用することはできません。したがって、使用できる範囲は0〜2147483647です。


0

川崎貴彦の回答で述べたように、javaは変更されたUTF-8の形式でUnicode文字列を表し、JVM仕様のCONSTANT_UTF8_info構造では、2バイトが長さに割り当てられます(文字列の文字数ではありません)。
答えを拡張するために、ASM jvmバイトコードライブラリのputUTF8メソッドには次のものが含まれています。

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);
      }
    }
    ...
}

ただし、コードポイントマッピング> 1バイトの場合は、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コードポイント範囲を見つけることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.