2012-05-09 32 views
40

thể trùng lặp:
Arrays constants can only be used in initializers errorTại sao các hằng số mảng chỉ được sử dụng trong các trình khởi tạo?

tôi đang học mảng, và tôi đã thông qua phương pháp cắt ngắn này khai báo và khởi tạo một mảng trong một dòng. Ví dụ:

int[] a = {1, 2, 3, 4, 5}; 

Nhưng khi tôi cố gắng thực hiện mã sau, tôi nhận được lỗi trình biên dịch này nói "hằng số mảng chỉ có thể được sử dụng trong trình khởi tạo".

int[] a; 
a = {1, 2, 3, 4}; 

Tại sao vậy?

+13

Đây không phải là bản sao. OP đang hỏi * tại sao * không * cách *. – Jeremy

+6

Meh; không tin rằng đó là một câu hỏi liên quan đến dupe nói "làm thế nào để tôi làm điều đó để nó hoạt động", câu hỏi này hỏi "tại sao cách khác thực sự không hiệu quả". Sự khác biệt dẫn đến các câu trả lời hoàn toàn khác nhau - câu hỏi này đã có * cách * để làm cho nó hoạt động. –

+0

Những loại câu hỏi này thú vị, nhưng khá nhiều điều không thể trả lời - tất cả những gì chúng ta có thể làm là suy đoán. Thật là thú vị khi hỏi điều này về bất cứ ai đã viết phần nào của spec, mặc dù, như là một thời điểm giảng dạy (tại sao bạn lại làm thiết kế này chứ không phải vậy?). – yshavit

Trả lời

0

Tôi java bạn chỉ có thể khởi tạo một mảng bằng phương thức đầu tiên. Bạn không thể gán một mảng. Hiểu được lý do tại sao có thể liên quan đến một số lý thuyết về cách thực hiện các mảng. Trình biên dịch phải biết làm thế nào lớn một mảng khi mảng được khai báo như vậy với khai báo và khởi tạo trên dòng đầu tiên, trình biên dịch có thể suy ra kích thước nhưng không phải với thứ hai.

+1

OP đã biết cái thứ hai không hoạt động và đang hỏi * tại sao *. Câu trả lời không giải quyết điều đó chút nào. –

+0

lý do tại sao người đọc có thể đọc không có phần tử nào trong dấu ngoặc nhọn và biết kích thước của nó trong trường hợp thứ nhất - int [] a = {1,2,3}; –

+0

java được đánh máy tĩnh nên trình biên dịch phải biết kích thước của mảng tại điểm khởi tạo để nó có thể cấp phát bộ nhớ cho mảng. – cobie

84

Không được phép vì JLS says so. Cú pháp chỉ được phép trong các khai báo và trong các biểu thức tạo mảng.

Sau đó cung cấp một cách khác để đạt được kết quả tương tự:

int[] a; 
a = new int[]{1, 2, 3, 4}; 

Đối với nguyên nhân sâu xa thực tế cho yêu cầu new T[], tôi đoán là như sau. Xem xét khởi tạo mảng sau:

{1, 2, 3, 4} 

Nó có thể được sử dụng để khởi mảng của các loại khác nhau:

new int[]{1, 2, 3, 4}; 
new float[]{1, 2, 3, 4}; 
new double[]{1, 2, 3, 4}; 

Nếu bit new T[] được không cần thiết, tôi nghi ngờ rằng trần {1, 2, 3, 4} có thể gây khó khăn trong phân tích ngữ nghĩa. Ở đây, tôi đang suy nghĩ về các trường hợp như:

void f(float[] x) { ... } 
void f(double[] x) { ... } 
void g() { 
    f({1, 2, 3, 4}); 
} 

Nếu cú ​​pháp này được cho phép, thông số ngôn ngữ sẽ phải đối phó với độ phức tạp của việc chọn chức năng gọi.

Trong một mạch tương tự, không rõ loại nào là loại {null}. Nó có thể là Object[], Integer[], Serializable[] và cứ tiếp tục như vậy.

Và cuối cùng, mảng trống {} sẽ là điều khó khăn nhất. Ở đây, chúng ta thậm chí không thể biết đó là một mảng các đối tượng hay một mảng các vô hướng.

Thay vì giải quyết tất cả những phức tạp này, có vẻ như các nhà thiết kế ngôn ngữ đã chọn để tránh chúng bằng cách yêu cầu cú pháp new T[].

+0

mà tôi biết nhưng câu hỏi của tôi là tại sao nó không được phép theo cách này? –

+0

Meh - trình biên dịch biết loại 'arrn'. Tôi có thể mua nó là một trình biên dịch đơn giản hóa, nhưng không có gì khó khăn về nó. –

+2

@DaveNewton: Không nhất thiết. Xem xét khả năng của '{1, 2, 3, 4}' được truyền vào một hàm bị quá tải cho 'float []' và 'double []'. Chuyện gì sẽ xảy ra? – NPE

5

Câu trả lời ngắn gọn là because the language spec says so.

Còn vì sao? Tôi nghi ngờ nó xuống đến nhập.Trong trường hợp đầu tiên, trình phân tích cú pháp/trình biên dịch biết nó nằm trong ngữ cảnh khởi tạo một biến mảng, và do đó các dấu ngoặc nhọn có thể được suy ra là một bộ khởi tạo mảng.

Trong trường hợp thứ hai, nó không phải ngay lập tức rõ ràng từ dòng những gì các dấu ngoặc nhọn có nghĩa là. Có lẽ typer chạy ở giai đoạn phân tích sau, sao cho không thể đoán được ý nghĩa của nó.

Lập luận này dường như có trọng lượng trong đó bạn có thể sử dụng một cú pháp rất giống nhau nếu bạn đặc biệt (và về mặt kỹ thuật dư thừa) khai báo loại một lần nữa:

int[] a; 
// then later 
a = new int[] { 1, 2, 3, 4 }; 
+1

Java nổi tiếng với cú pháp "không cần thiết về mặt kỹ thuật"; không có "kỹ thuật" về nó. –

0

Câu trả lời duy nhất mà bạn có thể nhận được là của thiên nhiên triết học. Quyết định không cho phép loại mảng tiềm ẩn phù hợp với nguyên tắc thiết kế chung của Java để giữ cho mọi thứ đơn giản và rõ ràng. Trong cùng một tĩnh mạch, bạn có thể hỏi tại sao mọi downcast phải rõ ràng, hoặc mỗi loại chuyển đổi thu hẹp. Java là một ngôn ngữ cổ xanh và rõ ràng + rõ ràng là giá trị cốt lõi của nó.

Các vấn đề liên quan