Độ dài tối đa của chuỗi trong Java - gọi phương thức length ()


150

Trong Java , kích thước tối đa mà một Stringđối tượng có thể có là gì, tham khảo lệnh length()gọi phương thức?

Tôi biết rằng length()trả về kích thước của a Stringlà a char [];


5
Mặc dù Stringvề mặt lý thuyết Integer.MAX_VALUE, độ dài của a là độ dài của một chuỗi ký tự trong nguồn dường như bị giới hạn chỉ với 65535 byte dữ liệu UTF-8.
200_success

Câu trả lời:


169

Xem xét phương thức Stringcủa lớp lengthtrả về một int, độ dài tối đa mà phương thức sẽ trả về sẽ Integer.MAX_VALUE2^31 - 1(hoặc khoảng 2 tỷ.)

Về độ dài và lập chỉ mục của các mảng, (chẳng hạn như char[], có lẽ là cách triển khai dữ liệu nội bộ cho Strings), Chương 10: Mảng của Đặc tả ngôn ngữ Java, Phiên bản Java SE 7 cho biết như sau:

Các biến chứa trong một mảng không có tên; thay vào đó, chúng được tham chiếu bởi các biểu thức truy cập mảng sử dụng các giá trị chỉ số nguyên không âm. Các biến này được gọi là các thành phần của mảng. Nếu một mảng có ncác thành phần, chúng ta nói nchiều dài của mảng; các thành phần của mảng được tham chiếu bằng các chỉ số nguyên từ 0đến n - 1, bao gồm.

Hơn nữa, việc lập chỉ mục phải theo intcác giá trị, như được đề cập trong Phần 10.4 :

Mảng phải được lập chỉ mục bởi intcác giá trị;

Do đó, dường như giới hạn là thực sự 2^31 - 1, vì đó là giá trị tối đa cho một intgiá trị không âm .

Tuy nhiên, có lẽ sẽ có những hạn chế khác, chẳng hạn như kích thước phân bổ tối đa cho một mảng.


26
Integer.MAX_VALUE là 2 ^ 31-1, thực sự. :)
Michael Myers

1
Người đàn ông trả lời tuyệt vời! Tôi đã xem mã nguồn String.java và nó đúng, 'Count' là biến int trả về độ dài của mảng char và mảng char được lưu trữ trên biến 'value' (như char []) kích thước Chuỗi có thể khoảng 2GB. Tất nhiên có thể có những hạn chế để phân bổ kích thước bộ nhớ như vậy. Cảm ơn!
taichi

5
Tôi vừa thử định nghĩa một chuỗi ký tự trong một chương trình java thế giới xin chào dài hơn 65546. javacđưa ra một lỗi về nghĩa đen đó quá dài:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
dlamblin

2
@dlamblin: Nghe có vẻ như giới hạn javacđối với String chữ (không phải Stringđối tượng), vì tôi không thể tìm thấy bất kỳ tham chiếu nào về giới hạn kích thước đối với Stringchữ trong Đặc tả ngôn ngữ Java và Đặc tả JVM. Tôi đã thử tạo một Stringký tự lớn hơn 100.000 ký tự và trình biên dịch Eclipse không gặp vấn đề gì khi biên dịch nó. (Và chạy chương trình đã có thể cho thấy rằng chữ có số lượng String.lengthlớn hơn 100.000.)
coobird

3
@Premraj Đó là ba năm trước vì vậy tôi phải suy nghĩ về nó. ;) Ý tôi là; để xây dựng một chuỗi có kích thước tối đa bạn cần rất nhiều bộ nhớ, có thể nhiều hơn bạn có. Bạn cần hai byte cho mỗi ký tự ~ 4GB, nhưng bạn cần xây dựng mã này từ StringBuilder hoặc char [], nghĩa là bạn cần thêm hai byte cho mỗi ký tự để tạo nó ở vị trí đầu tiên, tức là ~ 4 GB (ít nhất là tạm thời)
Peter Lawrey

25

java.io.DataInput.readUTF()java.io.DataOutput.writeUTF(String)nói rằng một Stringđối tượng được biểu thị bằng hai byte thông tin độ dài và biểu diễn UTF-8 đã sửa đổi của mỗi ký tự trong chuỗi. Điều này kết luận rằng độ dài của Chuỗi bị giới hạn bởi số byte của biểu diễn UTF-8 đã sửa đổi của chuỗi khi được sử dụng với DataInputDataOutput.

Ngoài ra, Đặc tảCONSTANT_Utf8_info được tìm thấy trong đặc tả máy ảo Java định nghĩa cấu trúc như sau.

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

Bạn có thể thấy rằng kích thước của 'chiều dài' là hai byte .

Rằng kiểu trả về của một phương thức nhất định (ví dụ String.length()) intkhông phải lúc nào cũng có nghĩa là giá trị tối đa được phép của nó là Integer.MAX_VALUE. Thay vào đó, trong hầu hết các trường hợp, intđược chọn chỉ vì lý do hiệu suất. Đặc tả ngôn ngữ Java nói rằng các số nguyên có kích thước nhỏ hơn kích thước intđược chuyển đổi thành inttrước khi tính toán (nếu bộ nhớ của tôi phục vụ cho tôi chính xác) và đó là một lý do để chọn intkhi không có lý do đặc biệt.

Độ dài tối đa tại thời gian biên dịch tối đa là 65536. Xin lưu ý lại rằng độ dài là số byte của biểu diễn UTF-8 đã sửa đổi , không phải số lượng ký tự trong một Stringđối tượng.

Stringcác đối tượng có thể có nhiều ký tự hơn trong thời gian chạy. Tuy nhiên, nếu bạn muốn sử dụng Stringcác đối tượng DataInputDataOutputgiao diện, tốt hơn là tránh sử dụng Stringcác đối tượng quá dài . Tôi đã tìm thấy giới hạn này khi tôi triển khai các tương đương Objective-C DataInput.readUTF()DataOutput.writeUTF(String).


1
Đây phải là câu trả lời mặc định.
Nick

20

Do các mảng phải được lập chỉ mục bằng các số nguyên, nên độ dài tối đa của một mảng là Integer.MAX_INT(2 31 -1 hoặc 2 147 483 647). Tất nhiên, điều này là giả sử bạn có đủ bộ nhớ để giữ một mảng có kích thước đó.


9

Tôi có iMac 2010 với 8GB RAM, chạy Eclipse neon.2 Release (4.6.2) với Java 1.8.0_25. Với đối số VM -Xmx6g, tôi đã chạy đoạn mã sau:

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

Bản in này:

Requested array size exceeds VM limit
1207959550

Vì vậy, có vẻ như kích thước mảng tối đa là ~ 1.207.959.549. Sau đó, tôi nhận ra rằng chúng ta không thực sự quan tâm nếu Java hết bộ nhớ: chúng ta chỉ tìm kích thước mảng tối đa (dường như là một hằng số được xác định ở đâu đó). Vì thế:

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

Bản in nào:

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

Vì vậy, có vẻ như tối đa là Integer.MAX_VALUE - 2 hoặc (2 ^ 31) - 3

PS Tôi không chắc tại sao StringBuildertối đa của tôi lại 1207959550trong khi char[]tối đa của tôi ở (2 ^ 31) -3. Có vẻ như AbstractStringBuildertăng gấp đôi kích thước bên trong của nó char[]để phát triển nó, do đó có thể gây ra vấn đề.


1
Một điều trị thực tế rất hữu ích cho câu hỏi
Pavlo Maistrenko


4

Kiểu trả về của phương thức length () của lớp String là int .

độ dài int int ()

Tham khảo http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()

Vậy giá trị tối đa của int là 2147483647 .

Chuỗi được coi là mảng char trong nội bộ, vì vậy việc lập chỉ mục được thực hiện trong phạm vi tối đa. Điều này có nghĩa là chúng tôi không thể lập chỉ mục cho thành viên thứ 2147483648. Vì vậy, độ dài tối đa của Chuỗi trong java là 2147483647.

Kiểu dữ liệu nguyên thủy int là 4 byte (32 bit) trong java. 1 bit (MSB) được sử dụng làm bit dấu , Phạm vi bị giới hạn trong phạm vi -2 ^ 31 đến 2 ^ 31-1 (-2147483648 đến 2147483647). Chúng tôi không thể sử dụng các giá trị âm để lập chỉ mục. Rõ ràng phạm vi chúng tôi có thể sử dụng là từ 0 đến 2147483647.


0

Như đã đề cập trong câu trả lời của Takahiko Kawasaki , java đại diện cho các chuỗi Unicode ở dạng UTF-8 đã sửa đổi và trong Cấu trúc JVM-Spec CONSTANT_UTF8_info , 2 byte được phân bổ theo chiều dài (chứ không phải là số ký tự của Chuỗi).
Để mở rộng câu trả lời, phương thức của thư viện ASM jvm bytecode , chứa: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);
      }
    }
    ...
}

Nhưng khi ánh xạ điểm mã> 1byte, nó gọi encodeUTF8phương thức:

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

Theo nghĩa này, độ dài chuỗi tối đa là 65535 byte, tức là độ dài mã hóa utf-8. và không charđược tính
Bạn có thể tìm thấy phạm vi điểm mã Unicode được sửa đổi của JVM, từ liên kết cấu trúc utf8 ở trên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.