回答:
考慮String
クラスのlength
メソッドの戻りはint
、メソッドによって返される最大長は次のようになりInteger.MAX_VALUE
である、2^31 - 1
(又は約20億)。
長さと配列のインデックス作成の観点から、(例えば、char[]
おそらく、内部データ表現をするために実装される方法である、String
S)、第10章:アレイのJava言語仕様のJava SE 7 Editionは、次のように述べています。
配列に含まれる変数には名前がありません。代わりに、非負の整数インデックス値を使用する配列アクセス式によって参照されます。これらの変数は、配列のコンポーネントと呼ばれ ます。配列に
n
コンポーネントがある場合は、配列n
の 長さです。配列のコンポーネントは、から0
までの整数インデックスを使用して参照されn - 1
ます。
さらに、10.4項int
で説明したように、インデックスは値である必要があります。
配列には
int
値でインデックスを付ける必要があります。
したがって、それ2^31 - 1
は非負のint
値の最大値であるため、制限は確かにであるように見えます。
ただし、おそらく配列に割り当て可能な最大サイズなど、他の制限もあるでしょう。
javac
が長すぎるというリテラルであることについてエラーを与える:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javac
ためString
リテラル(不String
iはサイズ制限への参照を見つけることができないなどのオブジェクト)、String
Java言語仕様とJVM仕様でリテラル。String
100,000文字を超えるリテラルを作ってみましたが、Eclipseコンパイラーではコンパイルに問題がありませんでした。(そして、プログラムを実行すると、リテラルがString.length
100,000より大きいことが示されました。)
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
オブジェクトをインターフェースで使用する場合はDataInput
、DataOutput
長すぎるオブジェクトを使用しないことをお勧めしString
ます。私はのObjective-Cの等価物を実現するとき、この制限を発見DataInput.readUTF()
し、DataOutput.writeUTF(String)
。
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で最大StringBuilder
に1207959550
なり、char[]
最大になっているのかわかりません。それはそれを成長させるためAbstractStringBuilder
にその内部のサイズを2倍char[]
にするようです、それでおそらく問題を引き起こします。
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です。
川崎貴彦の回答で述べたように、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コードポイント範囲を見つけることができます。
String
は理論的Integer.MAX_VALUE
にはですが、ソース内の文字列リテラルの長さは、UTF-8データの65535バイトのみに制限されているようです。