Panjang maksimum String di Jawa - metode panjang panggilan ()

150

Di Jawa , berapa ukuran maksimum suatu Stringobjek, merujuk pada length()pemanggilan metode?

Saya tahu bahwa length()mengembalikan ukuran a Stringsebagai char [];

taichi
sumber
5
Sementara panjang a Stringsecara teoritis Integer.MAX_VALUE, panjang string literal di sumber tampaknya terbatas hanya 65535 byte data UTF-8.
200_sukses

Jawaban:

169

Mempertimbangkan metode Stringkelas lengthmengembalikan suatu int, panjang maksimum yang akan dikembalikan oleh metode adalah Integer.MAX_VALUE, yaitu 2^31 - 1(atau sekitar 2 miliar).

Dalam hal panjang dan pengindeksan array, (seperti char[], yang mungkin adalah cara internal representasi data diimplementasikan untuk Strings), Bab 10: Array of The Java Language Specification, Java SE 7 Edition mengatakan sebagai berikut:

Variabel yang terkandung dalam array tidak memiliki nama; sebaliknya mereka direferensikan oleh ekspresi akses array yang menggunakan nilai indeks integer nonnegatif. Variabel-variabel ini disebut komponen - komponen array. Jika sebuah array memiliki nkomponen, kita katakan nadalah panjang array; komponen-komponen array direferensikan menggunakan indeks integer dari 0hingga n - 1, inklusif.

Selanjutnya, pengindeksan harus berdasarkan intnilai, seperti yang disebutkan dalam Bagian 10.4 :

Array harus diindeks oleh intnilai;

Oleh karena itu, tampaknya batasnya memang 2^31 - 1, karena itu adalah nilai maksimum untuk nilai bukan negatif int.

Namun, mungkin akan ada batasan lain, seperti ukuran maksimum yang dapat dialokasikan untuk sebuah array.

coobird
sumber
26
Integer.MAX_VALUE adalah 2 ^ 31-1, sebenarnya. :)
Michael Myers
1
Jawaban yang bagus! Saya melihat pada kode sumber String.java dan benar, 'count' adalah variabel int yang mengembalikan panjang array char, dan array char disimpan pada variabel 'value' (as char []) Ini berarti bahwa ukuran String bisa sekitar 2GB. Tentu saja mungkin ada batasan untuk mengalokasikan ukuran memori tersebut. Terima kasih!
taichi
5
Saya baru saja mencoba mendefinisikan string literal dalam program hello world java yang lebih panjang dari 65546. javacmemberikan kesalahan tentang literal yang terlalu panjang:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
dlamblin
2
@ dlamblin: Kedengarannya seperti batasan javacuntuk String literal (bukan Stringobjek), karena saya tidak dapat menemukan referensi untuk batas ukuran Stringliteral dalam Spesifikasi Bahasa Jawa dan Spesifikasi JVM. Saya mencoba membuat Stringliteral yang lebih besar dari 100.000 karakter, dan kompiler Eclipse tidak memiliki masalah dalam mengkompilasinya. (Dan menjalankan program ini dapat menunjukkan bahwa literal memiliki String.lengthlebih dari 100.000.)
coobird
3
@ Primraj Itu tiga tahun lalu jadi saya harus memikirkannya. ;) Yang saya maksud adalah; untuk membangun string berukuran maksimum, Anda perlu banyak memori, mungkin lebih dari yang Anda miliki. Anda memerlukan dua byte per karakter ~ 4GB, tetapi Anda harus membuatnya dari StringBuilder atau char [] yang artinya Anda memerlukan dua byte per karakter untuk membuatnya terlebih dahulu, yaitu yang lain ~ 4 GB (setidaknya sementara)
Peter Lawrey
25

java.io.DataInput.readUTF()dan java.io.DataOutput.writeUTF(String)mengatakan bahwa Stringobjek diwakili oleh dua byte informasi panjang dan representasi UTF-8 yang dimodifikasi dari setiap karakter dalam string. Ini menyimpulkan bahwa panjang String dibatasi oleh jumlah byte dari representasi UTF-8 yang dimodifikasi dari string ketika digunakan dengan DataInputdan DataOutput.

Selain itu, Spesifikasi yangCONSTANT_Utf8_info ditemukan dalam spesifikasi mesin virtual Java mendefinisikan struktur sebagai berikut.

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

Anda dapat menemukan bahwa ukuran 'panjang' adalah dua byte .

Bahwa tipe pengembalian dari metode tertentu (misalnya String.length()) inttidak selalu berarti bahwa nilai maksimum yang diizinkan adalah Integer.MAX_VALUE. Sebaliknya, dalam banyak kasus, intdipilih hanya karena alasan kinerja. Spesifikasi bahasa Java mengatakan bahwa bilangan bulat yang ukurannya lebih kecil daripada yang intdikonversi intsebelum perhitungan (jika ingatanku benar) dan itu adalah salah satu alasan untuk memilih intketika tidak ada alasan khusus.

Panjang maksimum pada waktu kompilasi paling banyak 65.536. Perhatikan lagi bahwa panjangnya adalah jumlah byte dari representasi UTF-8 yang dimodifikasi , bukan jumlah karakter dalam Stringobjek.

Stringobjek mungkin dapat memiliki lebih banyak karakter saat runtime. Namun, jika Anda ingin menggunakan Stringobjek dengan DataInputdan DataOutputantarmuka, lebih baik untuk menghindari menggunakan objek yang terlalu panjang String. Saya menemukan batasan ini ketika saya menerapkan setara Objective-C dari DataInput.readUTF()dan DataOutput.writeUTF(String).

Takahiko Kawasaki
sumber
1
Ini harus menjadi jawaban default.
Nick
20

Karena array harus diindeks dengan bilangan bulat, panjang maksimum array adalah Integer.MAX_INT(2 31 -1, atau 2 147 483 647). Ini dengan asumsi Anda memiliki cukup memori untuk menyimpan array ukuran itu, tentu saja.

Michael Myers
sumber
9

Saya memiliki iMac 2010 dengan 8GB RAM, menjalankan Eclipse Neon.2 Release (4.6.2) dengan Java 1.8.0_25. Dengan argumen VM -Xmx6g, saya menjalankan kode berikut:

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());

Ini mencetak:

Requested array size exceeds VM limit
1207959550

Jadi, tampaknya ukuran array maksimum adalah ~ 1.207.959.549. Kemudian saya menyadari bahwa kita sebenarnya tidak peduli jika Java kehabisan memori: kita hanya mencari ukuran array maksimum (yang tampaknya merupakan konstanta yang didefinisikan di suatu tempat). Begitu:

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

Yang mencetak:

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

Jadi, sepertinya maks adalah Integer.MAX_VALUE - 2, atau (2 ^ 31) - 3

PS Saya tidak yakin mengapa saya StringBuildermaxed out 1207959550sementara char[]maxed out saya di (2 ^ 31) -3. Tampaknya AbstractStringBuildermenggandakan ukuran internal char[]untuk menumbuhkannya, sehingga mungkin menyebabkan masalah.

dantiston
sumber
1
Perawatan praktis yang sangat berguna dari pertanyaan
Pavlo Maistrenko
5

rupanya itu terikat ke int, yaitu 0x7FFFFFFF (2147483647).

Francis
sumber
4

Tipe Return dari metode length () dari kelas String adalah int .

panjang int publik ()

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

Jadi nilai maksimum int adalah 2147483647 .

String dianggap sebagai array char secara internal, Jadi pengindeksan dilakukan dalam rentang maksimum. Ini berarti kita tidak dapat mengindeks anggota 2147483648. Jadi panjang maksimum String di java adalah 2147483647.

Int tipe data primitif adalah 4 byte (32 bit) di java. As 1 bit (MSB) digunakan sebagai bit tanda , Kisarannya dibatasi dalam -2 ^ 31 hingga 2 ^ 31-1 (-2147483648 hingga 2147483647). Kami tidak dapat menggunakan nilai negatif untuk pengindeksan. Jadi jelas rentang yang dapat kami gunakan adalah dari 0 hingga 2147483647.

Shanmugavel
sumber
0

Seperti yang disebutkan dalam jawaban Takahiko Kawasaki , java mewakili string Unicode dalam bentuk UTF-8 yang dimodifikasi dan dalam Struktur JVM-Spec CONSTANT_UTF8_info , 2 byte dialokasikan untuk panjang (dan bukan jumlah karakter String).
Untuk memperluas jawabannya, metode pustaka bytecode ASM jvm , berisi ini: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);
      }
    }
    ...
}

Tetapi ketika pemetaan kode-titik> 1byte, ia memanggil encodeUTF8metode:

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

Dalam pengertian ini, panjang string maks adalah 65535 byte, yaitu panjang enkode utf-8. dan tidak charmasuk hitungan
Anda dapat menemukan rentang kode-titik Unicode yang dimodifikasi dari JVM, dari tautan struct utf8 di atas.

DHS
sumber