Dizenin Java'daki maksimum uzunluğu - çağrı uzunluğu () yöntemi


150

In Java , maksimum boyutu nedir Stringatıfta bulunarak, nesne olabilir length()yöntemi çağrısı?

Bunu biliyorum length()dönüşü bir boyutu Stringbir şekilde char [];


5
A'nın uzunluğu Stringteorik olarak olsa da Integer.MAX_VALUE, kaynaktaki bir dizgi hazır bilgisinin uzunluğu yalnızca 65535 bayt UTF-8 verisi ile sınırlı görünmektedir .
200_success

Yanıtlar:


169

Göz önüne alındığında Stringsınıfının lengthyöntem döner bir intyöntem ile döndürülür maksimum uzunluğu olacaktır Integer.MAX_VALUEolan 2^31 - 1(ya da yaklaşık olarak 2 milyar.)

(Örneğin uzunlukları ve Dizilerin endeksleme oranı açısından char[]muhtemelen iç veri gösterimi için uygulanan yolu olan Strings), Bölüm 10: Diziler arasında Java Dil Şartname, Java SE 7 Sürümü şöyle demektedir:

Bir dizide yer alan değişkenlerin adı yoktur; bunun yerine, negatif olmayan tamsayı dizin değerleri kullanan dizi erişim ifadeleri tarafından başvurulur. Bu değişkenlere dizinin bileşenleri denir . Bir dizi varsa nbileşenleri, söyleyebiliriz nolan uzunluk dizisinin; Dizinin bileşenleri arasında bir tamsayıdır indeksler kullanılarak referans edilir 0için n - 1dahil,.

Ayrıca, indeksleme Bölüm 10.4'teint belirtildiği gibi değerlere göre olmalıdır :

Diziler intdeğerlere göre dizine eklenmelidir ;

Bu nedenle, 2^31 - 1negatif olmayan bir değer için maksimum değer olduğu için sınırın gerçekten olduğu görülmektedir int.

Bununla birlikte, muhtemelen bir dizi için maksimum ayrılabilir boyut gibi başka sınırlamalar olacaktır.


26
Tamsayı.MAX_VALUE aslında 2 ^ 31-1'dir. :)
Michael Myers

1
Harika cevap adamım! String.java kaynak koduna bir göz attım ve doğru, 'count' char dizisinin uzunluğunu döndüren int değişkeni ve char dizisi (char []) olarak 'value' değişkeninde saklanır Dize boyutu 2GB civarında olabilir. Elbette, bu tür bellek boyutunun tahsis edilmesinde sınırlamalar olabilir. Teşekkürler!
taichi

5
Ben sadece 65546'dan daha uzun bir merhaba dünya java programında bir dize değişmezi tanımlamaya çalıştım. javacBu değişmezlik çok uzun olması hakkında bir hata verir:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
dlamblin

2
@dlamblin: Java Dili Belirtimi ve JVM Belirtimi'nde değişmezlere ilişkin boyut sınırlarına başvuru bulamadığım javaciçin, String değişmez değerler ( Stringnesneler değil ) için bir sınırlama gibi geliyor String. String100.000 karakterden daha büyük bir hazır bilgi yazmayı denedim ve Eclipse derleyicisinin derlemesinde bir sorun yoktu. (Ve programı çalıştırmak, kelimenin tam anlamıyla String.length100.000'den daha büyük olduğunu gösterebildi .)
coobird

3
@Premraj Üç yıl önceydi, bu yüzden düşünmek zorunda kaldım. ;) Demek istediğim .... 'di; maksimum boyutlu bir dize oluşturmak için, muhtemelen zaten sahip olduğunuzdan daha fazla bellek gerekir. Karakter başına iki bayta ihtiyacınız var ~ 4GB, ancak bunu bir StringBuilder veya char [] öğesinden oluşturmanız gerekir; bu, ilk etapta oluşturmak için karakter başına iki bayta ihtiyacınız olduğu anlamına gelir, yani başka bir ~ 4 GB (en azından geçici olarak)
Peter Lawrey

25

java.io.DataInput.readUTF()ve java.io.DataOutput.writeUTF(String)bir Stringnesnenin iki bayt uzunluk bilgisi ve dizedeki her karakterin değiştirilmiş UTF-8 gösterimi ile temsil edildiğini varsayalım. Bu kullanıldığında String uzunluğu dize modifiye UTF-8 gösteriminin bayt sayısına göre sınırlı olduğu sonucuna DataInputve DataOutput.

Buna ek olarak, belirlenmesiCONSTANT_Utf8_info şu şekilde Java sanal makinesi tarifnamede, bulan yapısını tanımlar.

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

'Uzunluk' boyutunun iki bayt olduğunu görebilirsiniz .

Belirli bir yöntemin (örneğin String.length()) dönüş türünün inther zaman izin verilen maksimum değerinin olduğu anlamına gelmez Integer.MAX_VALUE. Bunun yerine, çoğu durumda, intsadece performans nedenleriyle seçilir. Java dili belirtimi, boyutu küçük olan tam sayıların hesaplamadan önce intdönüştürüldüğünü int(hafızam bana doğru bir şekilde hizmet ediyorsa) ve intözel bir neden olmadığında seçmek için bir neden olduğunu söylüyor.

Derleme süresindeki maksimum uzunluk en fazla 65536'dır. Uzunluğun, bir nesnedeki karakter sayısı değil, değiştirilmiş UTF-8 temsilinin bayt sayısı olduğunu unutmayın String.

Stringnesneler çalışma zamanında çok daha fazla karaktere sahip olabilir. Ancak, Stringnesneleri DataInputve DataOutputarabirimleriyle birlikte kullanmak istiyorsanız , çok uzun Stringnesneler kullanmaktan kaçınmak daha iyidir . Ben Objective-C eşdeğer uygulandığında bu sınırlamayı buldum DataInput.readUTF()ve DataOutput.writeUTF(String).


1
Bu varsayılan cevap olmalıdır.
Nick

20

Diziler tamsayılarla indekslenmesi gerektiğinden, bir dizinin maksimum uzunluğu Integer.MAX_INT(2 31 -1 veya 2 147 483 647) 'dir. Bu, elbette bu boyuttaki bir diziyi tutmak için yeterli belleğe sahip olduğunuzu varsayar.


9

Java 1.8.0_25 ile Eclipse Neon.2 Release (4.6.2) çalıştıran 8GB RAM ile 2010 iMac'im var. VM argümanı -Xmx6g ile aşağıdaki kodu çalıştırdım:

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

Bu yazdırır:

Requested array size exceeds VM limit
1207959550

Yani, maksimum dizi boyutu ~ 1,207,959,549. Sonra aslında Java'nın hafızasının bitip bitmediğini umursamadığımızı fark ettim: sadece maksimum dizi boyutunu arıyoruz (bu bir yerde tanımlanan bir sabit gibi görünüyor). Yani:

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

Hangi baskılar:

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

Yani, max tamsayı gibi görünüyor.MAX_VALUE - 2 veya (2 ^ 31) - 3

PS Emin değilim neden benim StringBuilderde maksimuma ulaştıkları dışarı 1207959550benim ederken char[](2 ^ 31) maxed -3. Görünüşe göre AbstractStringBuilderchar[]büyümesi onu büyütmek için iki katına çıkıyor , bu da muhtemelen soruna neden oluyor.


1
Sorunun çok yararlı bir pratik tedavisi
Pavlo Maistrenko

5

Görünüşe göre 0x7FFFFFFF (2147483647) olan bir int'e bağlı.


4

String sınıfının length () yönteminin Return türü int'dir .

kamu int uzunluğu ()

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

Yani int'nin maksimum değeri 2147483647'dir .

Dize dahili olarak char dizisi olarak kabul edilir, bu nedenle indeksleme maksimum aralıkta yapılır. Bu, 2147483648. üyeyi endeksleyemeyeceğimiz anlamına gelir. Yani java'da maksimum String uzunluğu 2147483647'dir.

İlkel veri türü int, java içinde 4 bayttır (32 bit). 1 bit (MSB) işaret biti olarak kullanıldığından , aralık -2 ^ 31 ila 2 ^ 31-1 (-2147483648 ila 2147483647) içinde sınırlandırılmıştır . Endeksleme için negatif değerler kullanamayız. Açıkçası kullanabileceğimiz aralık 0 ile 2147483647 arasındadır.


0

Takahiko Kawasaki'nin cevabında belirtildiği gibi , java, Unicode dizelerini değiştirilmiş UTF-8 biçiminde ve JVM-Spec CONSTANT_UTF8_info Yapısında temsil eder , uzunluğa 2 bayt tahsis edilir (String karakterlerinin sayısı değil).
Cevabı genişletmek için ASM jvm bayt kodu kitaplığının putUTF8yöntemi şunları içerir:

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

Ancak kod noktası eşlemesi> 1 bayt olduğunda, encodeUTF8yöntemi çağırır :

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

Bu anlamda, maksimum dize uzunluğu 65535 bayttır, yani utf-8 kodlama uzunluğu. değil charsaymak
Yukarıdaki utf8 yapı bağlantısından, JVM değiştirilmiş Unicode kod noktası aralığı bulabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.