Trường hợp thuộc tính chiều dài của mảng được xác định?


263

Chúng ta có thể xác định độ dài của một ArrayList<E>phương thức sử dụng phương thức công khai của nó size(), như

ArrayList<Integer> arr = new ArrayList(10);
int size = arr.size();

Tương tự như vậy, chúng ta có thể xác định chiều dài của một Arrayđối tượng bằng cách sử dụng thuộc lengthtính

String[] str = new String[10];
int size =  str.length;

Trong khi size()phương thức ArrayListđược định nghĩa bên trong ArrayListlớp, lengththuộc tính này Arrayđược định nghĩa ở đâu?


Về mặt tổ chức câu hỏi, tôi khuyên bạn nên đặt câu hỏi của bạn "thuộc tính độ dài của Mảng được xác định ở đâu?" trước tất cả các giải thích để ngăn bài đăng của bạn nghe giống như hướng dẫn của người mới bắt đầu.
NoName

Câu trả lời:


250

Mảng là các đối tượng đặc biệt trong java, chúng có một thuộc tính đơn giản có tên lengthfinal.

Không có "định nghĩa lớp" của một mảng (bạn không thể tìm thấy nó trong bất kỳ tệp. Class nào), chúng là một phần của chính ngôn ngữ.

10.7. Thành viên mảng

Các thành viên của một kiểu mảng là tất cả những điều sau đây:

  • Các public finallĩnh vực length, trong đó có số lượng các thành phần của mảng. lengthcó thể dương hoặc bằng không.
  • Các publicphương pháp clone, trong đó sẽ ghi đè phương thức cùng tên trong lớp Objectvà ném không kiểm tra trường hợp ngoại lệ. Kiểu trả về của clonephương thức của kiểu mảng T[]T[].

    Một bản sao của một mảng nhiều chiều là nông, có nghĩa là nó chỉ tạo ra một mảng mới. Các tiểu luận được chia sẻ.

  • Tất cả các thành viên được thừa hưởng từ lớp học Object; phương pháp duy nhất Objectkhông được kế thừa là clonephương pháp của nó .

Tài nguyên:


84
Cũng lưu ý rằng việc ArrayList.size()cung cấp số lượng đối tượng thực sự được lưu trữ trong mảng trong khi myArray.length( []) cung cấp "dung lượng". Đó là, nếu cho myArray = new int[10];, nó trả về 10. Nó không phải là số lượng đối tượng bạn đặt trong mảng.
wmorrison365

1
@Colin Làm thế nào các đối tượng mảng rất đặc biệt. Ý tôi là tại sao các nhà thiết kế cần làm cho nó trở nên đặc biệt và tại sao không cung cấp tệp lớp của một mảng?
Vikas Verma

5
@VikasVerma Tại sao các mảng không giống như các đối tượng? Vì lịch sử. Khi Java được thiết kế, hầu hết các nỗ lực đổi mới ngôn ngữ đều thất bại khi không giống với C về cú pháp và kiểu. Do đó, C ++, Objective-C và Java là một trong số ít các ngôn ngữ thoát khỏi tình trạng mù mờ trong thời đại đó. Java được thiết kế một cách có ý thức để bao gồm các dấu ngoặc nhọn, nguyên thủy và các mảng đơn giản để xuất hiện quen thuộc với các lập trình viên chính thống thời đó. Xem các cuộc phỏng vấn với James Gosling và những người khác của Sun. Một số người gắn bó với Bộ sưu tập cho OOP thuần túy và tránh các mảng đơn giản.
Basil Bourque

1
@VikasVerma, tại một số điểm, java phải được xây dựng trên công nghệ cấp thấp hơn. Nếu java không tồn tại, bạn không thể xây dựng nó bằng java. Bạn phải sử dụng C ++ (hoặc một cái gì đó khác, nhưng C ++ trong trường hợp này) để xây dựng một số trình biên dịch nguyên thủy cho phần còn lại của java để có bối cảnh cho sự tồn tại của chính nó. Bạn không thể có các lớp cho tất cả mọi thứ mà không chạm đáy đá nơi bạn mã hóa nó trong C ++. Làm thế nào chính xác bạn sẽ xây dựng một mảng trong java? Nếu bạn không thể sử dụng Listvì sử dụng mảng trong triển khai của họ.
Alexander Bird

nếu bạn muốn trả lời đúng như vậy , thì stackoverflow.com/a/50506451/1059372
Eugene

114

Về cơ bản, nó "đặc biệt", với hướng dẫn mã byte riêng của nó : arraylength. Vì vậy, phương pháp này:

public static void main(String[] args) {
    int x = args.length;
}

được biên dịch thành mã byte như thế này:

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   arraylength
   2:   istore_1
   3:   return

Vì vậy, nó không được truy cập như thể đó là một lĩnh vực bình thường. Thật vậy, nếu bạn cố gắng để có được nó như thể đó là một lĩnh vực bình thường, như thế này, nó sẽ thất bại:

// Fails...
Field field = args.getClass().getField("length");
System.out.println(field.get(args));

Thật không may, mô tả JLS của từng loại mảng có trường công khai cuối cùng lengthcó phần sai lệch :(


1
Tôi không nhớ chính xác một câu trích dẫn của Albert Einstein nhưng điều nó nói là "mọi người hiểu rất rõ điều đó chỉ có thể giải thích những điều đó theo cách rất đơn giản" tôi nghĩ rằng nó rất phù hợp với bạn :)
JAVA

@Jon Skeet Làm thế nào đối tượng mảng là đặc biệt Tôi có nghĩa là tại sao các nhà thiết kế cần làm cho nó đặc biệt và tại sao không cung cấp tệp lớp của một mảng?
Vikas Verma

2
@VikasVerma: Hãy nghĩ về kích thước của một đối tượng mảng. Tất cả các loại khác có kích thước cố định - mọi trường hợp có cùng kích thước, trong khi các mảng khác nhau dựa trên chiều dài của chúng. Đó chỉ là một ví dụ. Nếu bạn nghĩ rằng bạn có thể đạt được kết quả tương tự mà không cần sử dụng bất cứ điều gì đặc biệt, bạn nghĩ các trường của một lớp mảng sẽ như thế nào? Làm thế nào bạn sẽ đại diện int[]khi thuốc generic không áp dụng cho các loại nguyên thủy? (Và chết tiệt, dù sao thì thuốc generic vẫn không tồn tại trong một thời gian dài.) Bạn có thể thoát khỏi mà không có mảng bằng cách sử dụng danh sách được liên kết cho tất cả các bộ sưu tập, nhưng sẽ rất tệ cho hiệu quả.
Jon Skeet

@JonSkeet Nhưng còn loại lớp StringBuffer thì nó cũng có kích thước cố định? Vâng thực sự tôi đã suy nghĩ về thuốc generic nhưng bạn chỉ ra trước khi tôi hỏi Cảm ơn vì điều đó.
Vikas Verma

@VikasVerma: Bản StringBufferthân lớp học có, có - bởi vì nó có một tham chiếu đến mộtchar[] (hoặc ít nhất là, tôi không biết liệu nó có còn tồn tại không, ngoài tầm tay). Vì vậy, trong khi a StringBuilderchịu trách nhiệm cho nhiều bộ nhớ hơn, kích thước và bố cục ngay lập tức của nó được cố định.
Jon Skeet

18

Nó được định nghĩa trong đặc tả ngôn ngữ Java :

Các thành viên của một kiểu mảng là tất cả những điều sau đây:

  • Các public finallĩnh vực length, trong đó có số lượng các thành phần của mảng. lengthcó thể dương hoặc bằng không.

Vì có vô số kiểu mảng (đối với mỗi lớp có một kiểu mảng tương ứng, và sau đó có mảng đa chiều), nên chúng không thể được thực hiện trong tệp lớp; JVM phải thực hiện nó một cách nhanh chóng.


15

Mặc dù đây không phải là một câu trả lời trực tiếp cho câu hỏi, nó là một bổ sung cho đối số .lengthvs. .size()Tôi đã nghiên cứu một cái gì đó liên quan đến câu hỏi này vì vậy khi tôi bắt gặp nó tôi nhận thấy rằng định nghĩa được cung cấp ở đây

Độ dài trường cuối cùng công khai, chứa số lượng thành phần của mảng .

không "chính xác".

Độ dài trường chứa số lượng vị trí có sẵn để đặt một thành phần, không phải số lượng thành phần có trong mảng. Vì vậy, nó đại diện cho tổng bộ nhớ khả dụng được phân bổ cho mảng đó, chứ không phải bao nhiêu bộ nhớ được lấp đầy.

Phân bổ bộ nhớ mảng

Thí dụ:

static class StuffClass {
    int stuff;
    StuffClass(int stuff) {
        this.stuff = stuff;
    }
}

public static void main(String[] args) {

    int[] test = new int[5];
    test[0] = 2;
    test[1] = 33;
    System.out.println("Length of int[]:\t" + test.length);

    String[] test2 = new String[5];
    test2[0] = "2";
    test2[1] = "33";    
    System.out.println("Length of String[]:\t" + test2.length);

    StuffClass[] test3 = new StuffClass[5];
    test3[0] = new StuffClass(2);
    test3[1] = new StuffClass(33);
    System.out.println("Length of StuffClass[]:\t" + test3.length);         
}

Đầu ra:

Length of int[]:        5
Length of String[]:     5
Length of StuffClass[]: 5

Tuy nhiên, thuộc .size()tính của ArrayListkhông đưa ra số lượng phần tử trong danh sách:

ArrayList<Integer> intsList = new ArrayList<Integer>();
System.out.println("List size:\t" + intsList.size());
intsList.add(2);
System.out.println("List size:\t" + intsList.size());
intsList.add(33);
System.out.println("List size:\t" + intsList.size());

Đầu ra:

List size:  0
List size:  1
List size:  2

1
Đó là chính xác, vì tất cả các yếu tố được khởi tạo về không. Mảng không thể "trống rỗng"
Guido

Vâng, đó là chính xác những gì tôi nói. Nó không "chính xác". Nó vẫn có độ dài là 5 mặc dù không có gì được thêm vào mảng. Do đó, nó không "chính xác" chứa số lượng phần tử trong mảng. Nhận xét của bạn chỉ là một bổ sung cho câu trả lời của tôi, không phải là một lý do để làm cho nó không chính xác.
nem035

Nó có thể là "không chính xác" nếu bạn cố gắng phân biệt giữa nullcác yếu tố không và null. Nhưng sự khác biệt không hoạt động. Rốt cuộc, size()của (nói) a Listcũng có thể bao gồm nullcác giá trị.
Stephen C

Yup, về cơ bản, quan điểm của tôi là sizehoạt động linh hoạt, trong khi đó lengthlà một thuộc tính tĩnh ... thực tế là không gian trống còn lại trong một mảng được khởi tạo thành " Không giá trị " (tùy thuộc vào loại) không thực sự mâu thuẫn với điểm này.
nem035

5

đó là trường cuối cùng công khai, chứa số lượng thành phần của mảng (độ dài có thể dương hoặc bằng 0)

Do đó, một mảng có các trường và phương thức chung giống như lớp sau:

class A implements Cloneable, java.io.Serializable {
    public final int length = X;
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e.getMessage());
        }
    }
}

thêm thông tin tại

10.7 Thành viên mảng

http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html


0

Để trả lời đúng như vậy, thuộc tính độ dài này của mảng được định nghĩa ở đâu? Trong một đặc biệtObject header .

Dễ dàng xem qua JOL

 int [] ints = new int[23];
 System.out.println(ClassLayout.parseInstance(ints).toPrintable());

Một trong những dòng từ đầu ra này sẽ là:

OFFSET  SIZE      TYPE DESCRIPTION
16       4        (object header)   17 00 00 00 (00010111 00000000 00000000 00000000) (23)

Thông thường các đối tượng có hai tiêu đề (mark và klass), các mảng có thêm một tiêu đề luôn chiếm 4 byteschiều dài, như sizelà một int.


-1

Độ dài từ khóa hoạt động như một dữ liệu được xác định. Khi sử dụng trong một mảng, chúng ta có thể sử dụng nó để truy cập có bao nhiêu phần tử trong một mảng. Liên quan đến Chuỗi [], chúng ta có thể gọi phương thức length () được định nghĩa trong lớp String. Liên quan đến ArrayList, chúng ta có thể sử dụng phương thức size () được định nghĩa trong ArrayList. Lưu ý rằng khi tạo danh sách mảng với ArrayList <> (dung lượng), kích thước ban đầu () của danh sách mảng này bằng 0 do không có phần tử.

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.